@ooneex/pdf 0.0.18 → 1.0.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/README.md +264 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.js +4 -3
- package/dist/index.js.map +3 -3
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1 +1,265 @@
|
|
|
1
1
|
# @ooneex/pdf
|
|
2
|
+
|
|
3
|
+
PDF document toolkit for generating, editing, merging, splitting, and converting PDF files to images with page-level content extraction.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
✅ **Create PDFs** - Generate new PDF documents with metadata (title, author, keywords)
|
|
12
|
+
|
|
13
|
+
✅ **Add Pages** - Append pages with text content and configurable font size
|
|
14
|
+
|
|
15
|
+
✅ **Split PDFs** - Split documents into separate files by page ranges
|
|
16
|
+
|
|
17
|
+
✅ **Remove Pages** - Remove individual pages or page ranges from a document
|
|
18
|
+
|
|
19
|
+
✅ **Page to Image** - Convert PDF pages to PNG images with configurable scale
|
|
20
|
+
|
|
21
|
+
✅ **Text Extraction** - Extract text content from specific pages
|
|
22
|
+
|
|
23
|
+
✅ **Image Extraction** - Extract embedded images from PDF pages and save to disk
|
|
24
|
+
|
|
25
|
+
✅ **Metadata Management** - Read and update PDF metadata (title, author, dates, keywords)
|
|
26
|
+
|
|
27
|
+
✅ **Encrypted PDF Support** - Handle password-protected PDF files
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bun add @ooneex/pdf
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
### Creating a PDF
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { PDF } from '@ooneex/pdf';
|
|
41
|
+
|
|
42
|
+
const pdf = new PDF('/path/to/output.pdf');
|
|
43
|
+
|
|
44
|
+
await pdf.create({
|
|
45
|
+
title: 'My Document',
|
|
46
|
+
author: 'John Doe',
|
|
47
|
+
subject: 'Example PDF',
|
|
48
|
+
keywords: ['example', 'pdf'],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Adding Pages
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { PDF } from '@ooneex/pdf';
|
|
56
|
+
|
|
57
|
+
const pdf = new PDF('/path/to/document.pdf');
|
|
58
|
+
|
|
59
|
+
// Add an empty page
|
|
60
|
+
await pdf.addPage();
|
|
61
|
+
|
|
62
|
+
// Add a page with text content
|
|
63
|
+
await pdf.addPage({
|
|
64
|
+
content: 'Hello, World!\nThis is a new page.',
|
|
65
|
+
fontSize: 16,
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Splitting a PDF
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { PDF } from '@ooneex/pdf';
|
|
73
|
+
|
|
74
|
+
const pdf = new PDF('/path/to/document.pdf');
|
|
75
|
+
|
|
76
|
+
// Split into individual pages
|
|
77
|
+
for await (const result of pdf.split({ outputDir: '/output' })) {
|
|
78
|
+
console.log(`Pages ${result.pages.start}-${result.pages.end}: ${result.path}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Split by custom ranges
|
|
82
|
+
for await (const result of pdf.split({
|
|
83
|
+
outputDir: '/output',
|
|
84
|
+
ranges: [[1, 3], [5], [7, 10]],
|
|
85
|
+
})) {
|
|
86
|
+
console.log(result.path);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Removing Pages
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { PDF } from '@ooneex/pdf';
|
|
94
|
+
|
|
95
|
+
const pdf = new PDF('/path/to/document.pdf');
|
|
96
|
+
|
|
97
|
+
// Remove individual pages
|
|
98
|
+
const result = await pdf.removePages([2, 5]);
|
|
99
|
+
|
|
100
|
+
// Remove a range of pages
|
|
101
|
+
const result2 = await pdf.removePages([[3, 6]]);
|
|
102
|
+
|
|
103
|
+
// Mix individual pages and ranges
|
|
104
|
+
const result3 = await pdf.removePages([1, [4, 6], 10]);
|
|
105
|
+
console.log(result3.remainingPages);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Converting Pages to Images
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { PDF } from '@ooneex/pdf';
|
|
112
|
+
|
|
113
|
+
const pdf = new PDF('/path/to/document.pdf');
|
|
114
|
+
|
|
115
|
+
// Convert all pages
|
|
116
|
+
for await (const result of pdf.pagesToImages({ outputDir: '/images' })) {
|
|
117
|
+
console.log(`Page ${result.page}: ${result.path}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Convert a single page
|
|
121
|
+
const image = await pdf.pageToImage(1, {
|
|
122
|
+
outputDir: '/images',
|
|
123
|
+
prefix: 'doc',
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Extracting Text Content
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { PDF } from '@ooneex/pdf';
|
|
131
|
+
|
|
132
|
+
const pdf = new PDF('/path/to/document.pdf');
|
|
133
|
+
|
|
134
|
+
const text = await pdf.getPageContent(1);
|
|
135
|
+
console.log(text);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Extracting Images
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { PDF } from '@ooneex/pdf';
|
|
142
|
+
|
|
143
|
+
const pdf = new PDF('/path/to/document.pdf');
|
|
144
|
+
|
|
145
|
+
// Extract images from all pages
|
|
146
|
+
const images = await pdf.getImages({ outputDir: '/extracted' });
|
|
147
|
+
for (const img of images) {
|
|
148
|
+
console.log(`Page ${img.page}: ${img.path} (${img.width}x${img.height})`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Extract images from a specific page
|
|
152
|
+
const page1Images = await pdf.getImages({
|
|
153
|
+
outputDir: '/extracted',
|
|
154
|
+
pageNumber: 1,
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Reading and Updating Metadata
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { PDF } from '@ooneex/pdf';
|
|
162
|
+
|
|
163
|
+
const pdf = new PDF('/path/to/document.pdf');
|
|
164
|
+
|
|
165
|
+
// Read metadata
|
|
166
|
+
const metadata = await pdf.getMetadata();
|
|
167
|
+
console.log(metadata.title, metadata.author, metadata.pageCount);
|
|
168
|
+
|
|
169
|
+
// Update metadata
|
|
170
|
+
await pdf.updateMetadata({
|
|
171
|
+
title: 'Updated Title',
|
|
172
|
+
author: 'New Author',
|
|
173
|
+
keywords: ['updated', 'keywords'],
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Working with Encrypted PDFs
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { PDF } from '@ooneex/pdf';
|
|
181
|
+
|
|
182
|
+
const pdf = new PDF('/path/to/encrypted.pdf', {
|
|
183
|
+
password: 'secret',
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const metadata = await pdf.getMetadata();
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## API Reference
|
|
190
|
+
|
|
191
|
+
### Classes
|
|
192
|
+
|
|
193
|
+
#### `PDF`
|
|
194
|
+
|
|
195
|
+
Main class for all PDF operations.
|
|
196
|
+
|
|
197
|
+
**Constructor:**
|
|
198
|
+
```typescript
|
|
199
|
+
new PDF(source: string, options?: PDFOptionsType)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Parameters:**
|
|
203
|
+
- `source` - Path to the PDF file
|
|
204
|
+
- `options.password` - Password for encrypted PDFs
|
|
205
|
+
- `options.scale` - Scale factor for image conversion (default: 3)
|
|
206
|
+
|
|
207
|
+
**Methods:**
|
|
208
|
+
|
|
209
|
+
| Method | Returns | Description |
|
|
210
|
+
|--------|---------|-------------|
|
|
211
|
+
| `create(options?)` | `Promise<PDFCreateResultType>` | Create a new PDF document |
|
|
212
|
+
| `addPage(options?)` | `Promise<PDFAddPageResultType>` | Add a page to an existing PDF |
|
|
213
|
+
| `getMetadata()` | `Promise<PDFMetadataResultType>` | Get document metadata |
|
|
214
|
+
| `updateMetadata(options)` | `Promise<void>` | Update document metadata |
|
|
215
|
+
| `getPageCount()` | `Promise<number>` | Get total page count |
|
|
216
|
+
| `pagesToImages(options)` | `AsyncGenerator<PDFPageImageResultType>` | Convert all pages to images |
|
|
217
|
+
| `pageToImage(pageNumber, options)` | `Promise<PDFPageImageResultType>` | Convert a specific page to an image |
|
|
218
|
+
| `split(options)` | `AsyncGenerator<PDFSplitResultType>` | Split PDF into separate files |
|
|
219
|
+
| `removePages(pages)` | `Promise<PDFRemovePagesResultType>` | Remove pages from the PDF |
|
|
220
|
+
| `getPageContent(pageNumber)` | `Promise<string>` | Extract text content from a page |
|
|
221
|
+
| `getImages(options)` | `Promise<PDFGetImagesResultType>` | Extract embedded images |
|
|
222
|
+
|
|
223
|
+
### Key Types
|
|
224
|
+
|
|
225
|
+
#### `PDFCreateOptionsType`
|
|
226
|
+
|
|
227
|
+
Options for creating a PDF: `title`, `author`, `subject`, `keywords`, `producer`, `creator`.
|
|
228
|
+
|
|
229
|
+
#### `PDFSplitOptionsType`
|
|
230
|
+
|
|
231
|
+
Split options: `outputDir`, `ranges` (array of page numbers or `[start, end]` tuples), `prefix`.
|
|
232
|
+
|
|
233
|
+
#### `PDFToImagesOptionsType`
|
|
234
|
+
|
|
235
|
+
Image conversion options: `outputDir`, `prefix`.
|
|
236
|
+
|
|
237
|
+
#### `PDFGetImagesOptionsType`
|
|
238
|
+
|
|
239
|
+
Image extraction options: `outputDir`, `prefix`, `pageNumber`.
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
|
|
244
|
+
|
|
245
|
+
## Contributing
|
|
246
|
+
|
|
247
|
+
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
248
|
+
|
|
249
|
+
### Development Setup
|
|
250
|
+
|
|
251
|
+
1. Clone the repository
|
|
252
|
+
2. Install dependencies: `bun install`
|
|
253
|
+
3. Run tests: `bun run test`
|
|
254
|
+
4. Build the project: `bun run build`
|
|
255
|
+
|
|
256
|
+
### Guidelines
|
|
257
|
+
|
|
258
|
+
- Write tests for new features
|
|
259
|
+
- Follow the existing code style
|
|
260
|
+
- Update documentation for API changes
|
|
261
|
+
- Ensure all tests pass before submitting PR
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
Made with ❤️ by the Ooneex team
|
package/dist/index.d.ts
CHANGED
|
@@ -295,19 +295,19 @@ interface IPDF {
|
|
|
295
295
|
* @param options - Options including output directory and optional prefix
|
|
296
296
|
* @returns Array of page image results with page numbers and file paths
|
|
297
297
|
*/
|
|
298
|
-
|
|
298
|
+
pagesToImages(options: PDFToImagesOptionsType): AsyncGenerator<PDFPageImageResultType, void, unknown>;
|
|
299
299
|
/**
|
|
300
300
|
* Convert a specific page to an image and save to disk
|
|
301
301
|
* @param pageNumber - Page number (1-indexed)
|
|
302
302
|
* @param options - Options including output directory and optional prefix
|
|
303
303
|
*/
|
|
304
|
-
|
|
304
|
+
pageToImage(pageNumber: number, options: PDFToImagesOptionsType): Promise<PDFPageImageResultType>;
|
|
305
305
|
/**
|
|
306
306
|
* Split the PDF into separate documents and save to disk
|
|
307
307
|
* @param options - Split options with output directory, page ranges, and optional prefix
|
|
308
308
|
* @returns Array of split PDF results with page ranges and file paths
|
|
309
309
|
*/
|
|
310
|
-
split(options: PDFSplitOptionsType):
|
|
310
|
+
split(options: PDFSplitOptionsType): AsyncGenerator<PDFSplitResultType, void, unknown>;
|
|
311
311
|
/**
|
|
312
312
|
* Remove specified pages from the PDF
|
|
313
313
|
* @param pages - Page numbers to remove (1-indexed). Can be individual numbers or ranges [start, end]
|
|
@@ -430,11 +430,11 @@ declare class PDF implements IPDF {
|
|
|
430
430
|
*
|
|
431
431
|
* // Get content from page 1
|
|
432
432
|
* const content = await pdf.getPageContent(1);
|
|
433
|
-
* console.log(content);
|
|
433
|
+
* console.log(content); // "Lorem ipsum dolor sit amet..."
|
|
434
434
|
*
|
|
435
435
|
* // Get content from a specific page
|
|
436
436
|
* const page3Content = await pdf.getPageContent(3);
|
|
437
|
-
* console.log(page3Content); //
|
|
437
|
+
* console.log(page3Content); // Plain text content
|
|
438
438
|
* ```
|
|
439
439
|
*/
|
|
440
440
|
getPageContent(pageNumber: number): Promise<string>;
|
|
@@ -464,20 +464,20 @@ declare class PDF implements IPDF {
|
|
|
464
464
|
* @param options - Options including output directory and optional prefix
|
|
465
465
|
* @returns Array of page image results with page numbers and file paths
|
|
466
466
|
*/
|
|
467
|
-
|
|
467
|
+
pagesToImages(options: PDFToImagesOptionsType): AsyncGenerator<PDFPageImageResultType, void, unknown>;
|
|
468
468
|
/**
|
|
469
469
|
* Convert a specific page to an image and save to disk
|
|
470
470
|
* @param pageNumber - Page number (1-indexed)
|
|
471
471
|
* @param options - Options including output directory and optional prefix
|
|
472
472
|
* @returns Page image result with page number and file path
|
|
473
473
|
*/
|
|
474
|
-
|
|
474
|
+
pageToImage(pageNumber: number, options: PDFToImagesOptionsType): Promise<PDFPageImageResultType>;
|
|
475
475
|
/**
|
|
476
476
|
* Split the PDF into separate documents and save to disk
|
|
477
477
|
* @param options - Split options with output directory, page ranges, and optional prefix
|
|
478
478
|
* @returns Array of split PDF results with page ranges and file paths
|
|
479
479
|
*/
|
|
480
|
-
split(options: PDFSplitOptionsType):
|
|
480
|
+
split(options: PDFSplitOptionsType): AsyncGenerator<PDFSplitResultType, void, unknown>;
|
|
481
481
|
/**
|
|
482
482
|
* Remove specified pages from the PDF
|
|
483
483
|
* @param pages - Page numbers to remove (1-indexed). Can be individual numbers or ranges [start, end]
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import V from"path";import{PDFDocument as
|
|
3
|
-
`);for(let
|
|
2
|
+
import V from"path";import{PDFDocument as Y,rgb as O,StandardFonts as v}from"pdf-lib";import{pdf as R}from"pdf-to-img";import z from"sharp";import{extractImages as B,getDocumentProxy as S}from"unpdf";import{Exception as W}from"@ooneex/exception";import{HttpStatus as I}from"@ooneex/http-status";class G extends W{constructor(C,j={}){super(C,{status:I.Code.InternalServerError,data:j});this.name="PDFException"}}class T{source;options;constructor(C,j={}){this.source=V.join(...C.split(/[/\\]/)),this.options={scale:j.scale??3,...j.password!==void 0&&{password:j.password}}}async create(C={}){try{let j=await Y.create();if(C.title)j.setTitle(C.title);if(C.author)j.setAuthor(C.author);if(C.subject)j.setSubject(C.subject);if(C.keywords)j.setKeywords(C.keywords);if(C.producer)j.setProducer(C.producer);if(C.creator)j.setCreator(C.creator);let q=await j.save();return await Bun.write(this.source,q),{pageCount:j.getPageCount()}}catch(j){if(j instanceof G)throw j;throw new G("Failed to create PDF document",{source:this.source,error:j instanceof Error?j.message:String(j)})}}async addPage(C={}){try{let j=await Bun.file(this.source).arrayBuffer(),q=await Y.load(j,{ignoreEncryption:this.options.password!==void 0}),A=q.addPage();if(C.content){let J=await q.embedFont(v.Helvetica),L=C.fontSize??12,K=50,M=L*1.2,{height:Q}=A.getSize(),U=Q-50,Z=C.content.split(`
|
|
3
|
+
`);for(let _ of Z){if(U<50)break;A.drawText(_,{x:50,y:U,size:L,font:J,color:O(0,0,0)}),U-=M}}let H=await q.save();return await Bun.write(this.source,H),{pageCount:q.getPageCount()}}catch(j){if(j instanceof G)throw j;throw new G("Failed to add page to PDF",{source:this.source,error:j instanceof Error?j.message:String(j)})}}async getMetadata(){try{let C=await Bun.file(this.source).arrayBuffer(),j=await Y.load(C,{ignoreEncryption:this.options.password!==void 0,updateMetadata:!1});return{title:j.getTitle(),author:j.getAuthor(),subject:j.getSubject(),keywords:j.getKeywords(),producer:j.getProducer(),creator:j.getCreator(),creationDate:j.getCreationDate(),modificationDate:j.getModificationDate(),pageCount:j.getPageCount()}}catch(C){if(C instanceof G)throw C;throw new G("Failed to get PDF metadata",{source:this.source,error:C instanceof Error?C.message:String(C)})}}async updateMetadata(C){try{let j=await Bun.file(this.source).arrayBuffer(),q=await Y.load(j,{ignoreEncryption:this.options.password!==void 0});if(C.title!==void 0)q.setTitle(C.title);if(C.author!==void 0)q.setAuthor(C.author);if(C.subject!==void 0)q.setSubject(C.subject);if(C.keywords!==void 0)q.setKeywords(C.keywords);if(C.producer!==void 0)q.setProducer(C.producer);if(C.creator!==void 0)q.setCreator(C.creator);if(C.creationDate!==void 0)q.setCreationDate(C.creationDate);if(C.modificationDate!==void 0)q.setModificationDate(C.modificationDate);let A=await q.save();await Bun.write(this.source,A)}catch(j){if(j instanceof G)throw j;throw new G("Failed to update PDF metadata",{source:this.source,error:j instanceof Error?j.message:String(j)})}}async getPageCount(){try{let C=await Bun.file(this.source).arrayBuffer();return(await Y.load(C,{ignoreEncryption:this.options.password!==void 0,updateMetadata:!1})).getPageCount()}catch(C){throw new G("Failed to get page count",{source:this.source,error:C instanceof Error?C.message:String(C)})}}async getPageContent(C){if(C<1||!Number.isInteger(C))throw new G("Page number must be a positive integer",{pageNumber:C});try{let j=await Bun.file(this.source).arrayBuffer(),q=await S(new Uint8Array(j)),A=q.numPages;if(C>A)throw new G("Page number exceeds total pages",{pageNumber:C,totalPages:A});return(await(await q.getPage(C)).getTextContent()).items.filter((K)=>("str"in K)).map((K)=>("hasEOL"in K)&&K.hasEOL?`${K.str}
|
|
4
|
+
`:K.str).join("").trim()}catch(j){if(j instanceof G)throw j;throw new G("Failed to get page content",{source:this.source,pageNumber:C,error:j instanceof Error?j.message:String(j)})}}async getImages(C){let{pageNumber:j}=C;if(j!==void 0&&(j<1||!Number.isInteger(j)))throw new G("Page number must be a positive integer",{pageNumber:j});let q=V.join(...C.outputDir.split(/[/\\]/)),A=C.prefix??"image";try{let H=await Bun.file(this.source).arrayBuffer(),J=await S(new Uint8Array(H)),L=J.numPages;if(j!==void 0&&j>L)throw new G("Page number exceeds total pages",{pageNumber:j,totalPages:L});let K=async(Q)=>{let U=await B(J,Q),Z=[],_=0;for(let X of U){_++;let w=`${A}-p${Q}-${_}.png`,$=V.join(q,w),k=await z(X.data,{raw:{width:X.width,height:X.height,channels:X.channels}}).png().toBuffer();await Bun.write($,k),Z.push({page:Q,path:$,width:X.width,height:X.height})}return Z};if(j!==void 0)return await K(j);return(await Promise.all(Array.from({length:L},(Q,U)=>K(U+1)))).flat()}catch(H){if(H instanceof G)throw H;throw new G("Failed to extract images from PDF",{source:this.source,outputDir:q,pageNumber:j,error:H instanceof Error?H.message:String(H)})}}async*pagesToImages(C){let j=V.join(...C.outputDir.split(/[/\\]/)),q=C.prefix??"page",A=globalThis.pdfjsWorker;globalThis.pdfjsWorker=void 0;try{let H=await R(this.source,this.options),J=1;for await(let L of H){let K=`${q}-${J}.png`,M=V.join(j,K);await Bun.write(M,Buffer.from(L)),yield{page:J,path:M},J++}globalThis.pdfjsWorker=A}catch(H){throw globalThis.pdfjsWorker=A,new G("Failed to convert PDF to images",{source:this.source,outputDir:j,error:H instanceof Error?H.message:String(H)})}}async pageToImage(C,j){if(C<1||!Number.isInteger(C))throw new G("Page number must be a positive integer",{pageNumber:C});let q=V.join(...j.outputDir.split(/[/\\]/)),A=j.prefix??"page",H=globalThis.pdfjsWorker;globalThis.pdfjsWorker=void 0;try{let J=await R(this.source,this.options);if(C>J.length)throw new G("Page number exceeds total pages",{pageNumber:C,totalPages:J.length});let L=await J.getPage(C),K=`${A}-${C}.png`,M=V.join(q,K);return await Bun.write(M,Buffer.from(L)),globalThis.pdfjsWorker=H,{page:C,path:M}}catch(J){if(globalThis.pdfjsWorker=H,J instanceof G)throw J;throw new G("Failed to get page image",{source:this.source,pageNumber:C,outputDir:q,error:J instanceof Error?J.message:String(J)})}}async*split(C){let j=V.join(...C.outputDir.split(/[/\\]/)),q=C.prefix??"page";try{let A=await Bun.file(this.source).arrayBuffer(),H=await Y.load(A,{ignoreEncryption:this.options.password!==void 0}),J=H.getPageCount();if(J===0)throw new G("PDF has no pages",{source:this.source});let L=this.normalizeRanges(C.ranges,J);for(let{start:K,end:M}of L)if(K<1||M>J||K>M)throw new G("Invalid page range",{start:K,end:M,totalPages:J});for(let{start:K,end:M}of L){let Q=await Y.create(),U=Array.from({length:M-K+1},($,k)=>K-1+k),Z=await Q.copyPages(H,U);for(let $ of Z)Q.addPage($);let _=await Q.save(),X=K===M?`${q}-${K}.pdf`:`${q}-${K}-${M}.pdf`,w=V.join(j,X);await Bun.write(w,_),yield{pages:{start:K,end:M},path:w}}}catch(A){if(A instanceof G)throw A;throw new G("Failed to split PDF",{source:this.source,outputDir:j,error:A instanceof Error?A.message:String(A)})}}async removePages(C){try{let j=await Bun.file(this.source).arrayBuffer(),q=await Y.load(j,{ignoreEncryption:this.options.password!==void 0}),A=q.getPageCount();if(A===0)throw new G("PDF has no pages",{source:this.source});let H=this.normalizePageNumbers(C,A);if(H.length===0)throw new G("No valid pages specified for removal",{pages:C});if(H.length>=A)throw new G("Cannot remove all pages from PDF",{pagesToRemove:H,totalPages:A});let J=[...H].sort((K,M)=>M-K);for(let K of J)q.removePage(K-1);let L=await q.save();return await Bun.write(this.source,L),{remainingPages:q.getPageCount()}}catch(j){if(j instanceof G)throw j;throw new G("Failed to remove pages from PDF",{source:this.source,pages:C,error:j instanceof Error?j.message:String(j)})}}normalizePageNumbers(C,j){let q=new Set;for(let A of C)if(typeof A==="number"){if(A>=1&&A<=j&&Number.isInteger(A))q.add(A)}else{let[H,J]=A;if(H<=J){for(let L=Math.max(1,H);L<=Math.min(j,J);L++)if(Number.isInteger(L))q.add(L)}}return Array.from(q)}normalizeRanges(C,j){if(!C||C.length===0)return Array.from({length:j},(q,A)=>({start:A+1,end:A+1}));return C.map((q)=>{if(typeof q==="number")return{start:q,end:q};return{start:q[0],end:q[1]}})}}export{G as PDFException,T as PDF};
|
|
4
5
|
|
|
5
|
-
//# debugId=
|
|
6
|
+
//# debugId=D77D34577E7BB37C64756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["src/PDF.ts", "src/PDFException.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import path from \"node:path\";\nimport { PDFDocument, rgb, StandardFonts } from \"pdf-lib\";\nimport { pdf } from \"pdf-to-img\";\nimport sharp from \"sharp\";\nimport { extractImages, extractText, getDocumentProxy } from \"unpdf\";\nimport { PDFException } from \"./PDFException\";\nimport type {\n IPDF,\n PDFAddPageOptionsType,\n PDFAddPageResultType,\n PDFCreateOptionsType,\n PDFCreateResultType,\n PDFExtractedImageType,\n PDFGetImagesOptionsType,\n PDFGetImagesResultType,\n PDFMetadataResultType,\n PDFOptionsType,\n PDFPageImageResultType,\n PDFRemovePagesResultType,\n PDFSplitOptionsType,\n PDFSplitResultType,\n PDFToImagesOptionsType,\n PDFUpdateMetadataOptionsType,\n} from \"./types\";\n\nexport class PDF implements IPDF {\n private readonly source: string;\n private readonly options: PDFOptionsType;\n\n /**\n * Create a new PDF instance\n * @param source - Path to PDF file\n * @param options - Options for PDF processing\n */\n constructor(source: string, options: PDFOptionsType = {}) {\n this.source = path.join(...source.split(/[/\\\\]/));\n this.options = {\n scale: options.scale ?? 3,\n ...(options.password !== undefined && { password: options.password }),\n };\n }\n\n /**\n * Create a new PDF document and save to the source path\n * @param options - Optional content and metadata options for the PDF document\n * @returns Result containing the page count\n *\n * @example\n * ```typescript\n * // Create a simple empty PDF\n * const pdf = new PDF(\"/path/to/output.pdf\");\n * const result = await pdf.create();\n *\n * // Create a PDF with metadata\n * const pdf = new PDF(\"/path/to/output.pdf\");\n * const result = await pdf.create({\n * title: \"My Document\",\n * author: \"John Doe\",\n * subject: \"Example PDF\",\n * keywords: [\"example\", \"pdf\", \"document\"],\n * creator: \"My App\",\n * producer: \"pdf-lib\",\n * });\n * ```\n */\n public async create(options: PDFCreateOptionsType = {}): Promise<PDFCreateResultType> {\n try {\n const pdfDoc = await PDFDocument.create();\n\n // Set metadata if provided\n if (options.title) {\n pdfDoc.setTitle(options.title);\n }\n if (options.author) {\n pdfDoc.setAuthor(options.author);\n }\n if (options.subject) {\n pdfDoc.setSubject(options.subject);\n }\n if (options.keywords) {\n pdfDoc.setKeywords(options.keywords);\n }\n if (options.producer) {\n pdfDoc.setProducer(options.producer);\n }\n if (options.creator) {\n pdfDoc.setCreator(options.creator);\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n\n return {\n pageCount: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to create PDF document\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Add a page to an existing PDF document\n * @param options - Optional content options for the page\n * @returns Result containing the total page count\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Add an empty page\n * await pdf.addPage();\n *\n * // Add a page with content\n * await pdf.addPage({\n * content: \"Hello, World!\",\n * fontSize: 24,\n * });\n * ```\n */\n public async addPage(options: PDFAddPageOptionsType = {}): Promise<PDFAddPageResultType> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n const page = pdfDoc.addPage();\n\n // Add content if provided\n if (options.content) {\n const font = await pdfDoc.embedFont(StandardFonts.Helvetica);\n const fontSize = options.fontSize ?? 12;\n const margin = 50;\n const lineHeight = fontSize * 1.2;\n\n const { height } = page.getSize();\n let y = height - margin;\n\n const lines = options.content.split(\"\\n\");\n\n for (const line of lines) {\n if (y < margin) {\n break;\n }\n\n page.drawText(line, {\n x: margin,\n y,\n size: fontSize,\n font,\n color: rgb(0, 0, 0),\n });\n\n y -= lineHeight;\n }\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n\n return {\n pageCount: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to add page to PDF\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get metadata from the PDF document\n * @returns PDF metadata including title, author, dates, and page count\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n * const metadata = await pdf.getMetadata();\n *\n * console.log(metadata.title);\n * console.log(metadata.author);\n * console.log(metadata.pageCount);\n * ```\n */\n public async getMetadata(): Promise<PDFMetadataResultType> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n updateMetadata: false,\n });\n\n return {\n title: pdfDoc.getTitle(),\n author: pdfDoc.getAuthor(),\n subject: pdfDoc.getSubject(),\n keywords: pdfDoc.getKeywords(),\n producer: pdfDoc.getProducer(),\n creator: pdfDoc.getCreator(),\n creationDate: pdfDoc.getCreationDate(),\n modificationDate: pdfDoc.getModificationDate(),\n pageCount: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to get PDF metadata\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Update metadata of an existing PDF document\n * @param options - Metadata options to update\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n * await pdf.updateMetadata({\n * title: \"Updated Title\",\n * author: \"New Author\",\n * subject: \"Updated Subject\",\n * keywords: [\"updated\", \"keywords\"],\n * producer: \"My App\",\n * creator: \"pdf-lib\",\n * creationDate: new Date(\"2020-01-01\"),\n * modificationDate: new Date(),\n * });\n * ```\n */\n public async updateMetadata(options: PDFUpdateMetadataOptionsType): Promise<void> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n if (options.title !== undefined) {\n pdfDoc.setTitle(options.title);\n }\n if (options.author !== undefined) {\n pdfDoc.setAuthor(options.author);\n }\n if (options.subject !== undefined) {\n pdfDoc.setSubject(options.subject);\n }\n if (options.keywords !== undefined) {\n pdfDoc.setKeywords(options.keywords);\n }\n if (options.producer !== undefined) {\n pdfDoc.setProducer(options.producer);\n }\n if (options.creator !== undefined) {\n pdfDoc.setCreator(options.creator);\n }\n if (options.creationDate !== undefined) {\n pdfDoc.setCreationDate(options.creationDate);\n }\n if (options.modificationDate !== undefined) {\n pdfDoc.setModificationDate(options.modificationDate);\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to update PDF metadata\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get the total number of pages in the PDF\n */\n public async getPageCount(): Promise<number> {\n try {\n const document = await pdf(this.source, this.options);\n return document.length;\n } catch (error) {\n throw new PDFException(\"Failed to get page count\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get the text content of a specific page\n * @param pageNumber - Page number (1-indexed)\n * @returns Extracted text content from the page\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Get content from page 1\n * const content = await pdf.getPageContent(1);\n * console.log(content);\n *\n * // Get content from a specific page\n * const page3Content = await pdf.getPageContent(3);\n * console.log(page3Content); // Text content of page 3\n * ```\n */\n public async getPageContent(pageNumber: number): Promise<string> {\n if (pageNumber < 1 || !Number.isInteger(pageNumber)) {\n throw new PDFException(\"Page number must be a positive integer\", {\n pageNumber,\n });\n }\n\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n const document = await getDocumentProxy(new Uint8Array(sourceBytes));\n\n const totalPages = document.numPages;\n\n if (pageNumber > totalPages) {\n throw new PDFException(\"Page number exceeds total pages\", {\n pageNumber,\n totalPages,\n });\n }\n\n const { text } = await extractText(document, { mergePages: false });\n\n return text[pageNumber - 1] ?? \"\";\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to get page content\", {\n source: this.source,\n pageNumber,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Extract images from PDF pages and save to disk\n * @param options - Options including output directory, optional prefix, and optional page number\n * @returns Result containing total pages and array of extracted images with file paths\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Extract images from all pages\n * const images = await pdf.getImages({ outputDir: \"/output\" });\n * console.log(`Found ${images.length} images`);\n *\n * // Extract images from a specific page\n * const page1Images = await pdf.getImages({ outputDir: \"/output\", prefix: \"doc\", pageNumber: 1 });\n * for (const image of page1Images) {\n * console.log(`Image: ${image.path}, ${image.width}x${image.height}`);\n * }\n * ```\n */\n public async getImages(options: PDFGetImagesOptionsType): Promise<PDFGetImagesResultType> {\n const { pageNumber } = options;\n\n if (pageNumber !== undefined && (pageNumber < 1 || !Number.isInteger(pageNumber))) {\n throw new PDFException(\"Page number must be a positive integer\", {\n pageNumber,\n });\n }\n\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"image\";\n\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n const document = await getDocumentProxy(new Uint8Array(sourceBytes));\n const totalPages = document.numPages;\n\n if (pageNumber !== undefined && pageNumber > totalPages) {\n throw new PDFException(\"Page number exceeds total pages\", {\n pageNumber,\n totalPages,\n });\n }\n\n const images: PDFExtractedImageType[] = [];\n let imageIndex = 0;\n\n const processPage = async (page: number) => {\n const pageImages = await extractImages(document, page);\n for (const img of pageImages) {\n imageIndex++;\n const fileName = `${prefix}-${page}-${imageIndex}.png`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n // Convert raw image data to PNG using sharp\n const pngBuffer = await sharp(img.data, {\n raw: {\n width: img.width,\n height: img.height,\n channels: img.channels,\n },\n })\n .png()\n .toBuffer();\n\n await Bun.write(filePath, pngBuffer);\n\n images.push({\n page,\n path: filePath,\n width: img.width,\n height: img.height,\n });\n }\n };\n\n if (pageNumber !== undefined) {\n await processPage(pageNumber);\n } else {\n for (let page = 1; page <= totalPages; page++) {\n await processPage(page);\n }\n }\n\n return images;\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to extract images from PDF\", {\n source: this.source,\n outputDir: normalizedOutputDir,\n pageNumber,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Convert all pages to images and save to disk\n * @param options - Options including output directory and optional prefix\n * @returns Array of page image results with page numbers and file paths\n */\n public async toImages(options: PDFToImagesOptionsType): Promise<PDFPageImageResultType[]> {\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"page\";\n\n try {\n const document = await pdf(this.source, this.options);\n const results: PDFPageImageResultType[] = [];\n let pageNumber = 1;\n\n for await (const image of document) {\n const fileName = `${prefix}-${pageNumber}.png`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n await Bun.write(filePath, Buffer.from(image));\n\n results.push({\n page: pageNumber,\n path: filePath,\n });\n pageNumber++;\n }\n\n return results;\n } catch (error) {\n throw new PDFException(\"Failed to convert PDF to images\", {\n source: this.source,\n outputDir: normalizedOutputDir,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Convert a specific page to an image and save to disk\n * @param pageNumber - Page number (1-indexed)\n * @param options - Options including output directory and optional prefix\n * @returns Page image result with page number and file path\n */\n public async getPageImage(pageNumber: number, options: PDFToImagesOptionsType): Promise<PDFPageImageResultType> {\n if (pageNumber < 1 || !Number.isInteger(pageNumber)) {\n throw new PDFException(\"Page number must be a positive integer\", {\n pageNumber,\n });\n }\n\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"page\";\n\n try {\n const document = await pdf(this.source, this.options);\n\n if (pageNumber > document.length) {\n throw new PDFException(\"Page number exceeds total pages\", {\n pageNumber,\n totalPages: document.length,\n });\n }\n\n const image = await document.getPage(pageNumber);\n\n const fileName = `${prefix}-${pageNumber}.png`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n await Bun.write(filePath, Buffer.from(image));\n\n return {\n page: pageNumber,\n path: filePath,\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to get page image\", {\n source: this.source,\n pageNumber,\n outputDir: normalizedOutputDir,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Split the PDF into separate documents and save to disk\n * @param options - Split options with output directory, page ranges, and optional prefix\n * @returns Array of split PDF results with page ranges and file paths\n */\n public async split(options: PDFSplitOptionsType): Promise<PDFSplitResultType[]> {\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"page\";\n\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const sourcePdf = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n const totalPages = sourcePdf.getPageCount();\n\n if (totalPages === 0) {\n throw new PDFException(\"PDF has no pages\", {\n source: this.source,\n });\n }\n\n const ranges = this.normalizeRanges(options.ranges, totalPages);\n const results: PDFSplitResultType[] = [];\n\n for (const range of ranges) {\n const { start, end } = range;\n\n if (start < 1 || end > totalPages || start > end) {\n throw new PDFException(\"Invalid page range\", {\n start,\n end,\n totalPages,\n });\n }\n\n const newPdf = await PDFDocument.create();\n const pageIndices = Array.from({ length: end - start + 1 }, (_, i) => start - 1 + i);\n const copiedPages = await newPdf.copyPages(sourcePdf, pageIndices);\n\n for (const page of copiedPages) {\n newPdf.addPage(page);\n }\n\n const pdfBytes = await newPdf.save();\n\n const fileName = start === end ? `${prefix}-${start}.pdf` : `${prefix}-${start}-${end}.pdf`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n await Bun.write(filePath, pdfBytes);\n\n results.push({\n pages: { start, end },\n path: filePath,\n });\n }\n\n return results;\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to split PDF\", {\n source: this.source,\n outputDir: normalizedOutputDir,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Remove specified pages from the PDF\n * @param pages - Page numbers to remove (1-indexed). Can be individual numbers or ranges [start, end]\n * @returns Result with remaining page count and PDF buffer\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Remove individual pages (pages 2 and 5)\n * const result1 = await pdf.removePages([2, 5]);\n *\n * // Remove a range of pages (pages 3 to 6)\n * const result2 = await pdf.removePages([[3, 6]]);\n *\n * // Remove mixed: individual pages and ranges (pages 1, 4-6, and 10)\n * const result3 = await pdf.removePages([1, [4, 6], 10]);\n *\n * console.log(result3.remainingPages); // Number of pages left\n * console.log(result3.buffer); // Buffer containing the resulting PDF\n *\n * // Save to file\n * await Bun.write(\"/path/to/output.pdf\", result3.buffer);\n * ```\n */\n public async removePages(pages: (number | [number, number])[]): Promise<PDFRemovePagesResultType> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n const totalPages = pdfDoc.getPageCount();\n\n if (totalPages === 0) {\n throw new PDFException(\"PDF has no pages\", {\n source: this.source,\n });\n }\n\n // Normalize page numbers to remove into a flat sorted array\n const pagesToRemove = this.normalizePageNumbers(pages, totalPages);\n\n if (pagesToRemove.length === 0) {\n throw new PDFException(\"No valid pages specified for removal\", {\n pages,\n });\n }\n\n if (pagesToRemove.length >= totalPages) {\n throw new PDFException(\"Cannot remove all pages from PDF\", {\n pagesToRemove,\n totalPages,\n });\n }\n\n // Remove pages in reverse order to maintain correct indices\n const sortedDescending = [...pagesToRemove].sort((a, b) => b - a);\n for (const pageNum of sortedDescending) {\n pdfDoc.removePage(pageNum - 1); // Convert to 0-indexed\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n\n return {\n remainingPages: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to remove pages from PDF\", {\n source: this.source,\n pages,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Normalize page numbers into a flat array of unique valid page numbers\n */\n private normalizePageNumbers(pages: (number | [number, number])[], totalPages: number): number[] {\n const pageSet = new Set<number>();\n\n for (const page of pages) {\n if (typeof page === \"number\") {\n if (page >= 1 && page <= totalPages && Number.isInteger(page)) {\n pageSet.add(page);\n }\n } else {\n const [start, end] = page;\n if (start <= end) {\n for (let i = Math.max(1, start); i <= Math.min(totalPages, end); i++) {\n if (Number.isInteger(i)) {\n pageSet.add(i);\n }\n }\n }\n }\n }\n\n return Array.from(pageSet);\n }\n\n /**\n * Normalize page ranges for splitting\n * If no ranges provided, creates individual page ranges\n */\n private normalizeRanges(\n ranges: PDFSplitOptionsType[\"ranges\"] | undefined,\n totalPages: number,\n ): { start: number; end: number }[] {\n if (!ranges || ranges.length === 0) {\n return Array.from({ length: totalPages }, (_, i) => ({\n start: i + 1,\n end: i + 1,\n }));\n }\n\n return ranges.map((range) => {\n if (typeof range === \"number\") {\n return { start: range, end: range };\n }\n return { start: range[0], end: range[1] };\n });\n }\n}\n",
|
|
5
|
+
"import path from \"node:path\";\nimport { PDFDocument, rgb, StandardFonts } from \"pdf-lib\";\nimport { pdf } from \"pdf-to-img\";\nimport sharp from \"sharp\";\nimport { extractImages, getDocumentProxy } from \"unpdf\";\nimport { PDFException } from \"./PDFException\";\nimport type {\n IPDF,\n PDFAddPageOptionsType,\n PDFAddPageResultType,\n PDFCreateOptionsType,\n PDFCreateResultType,\n PDFExtractedImageType,\n PDFGetImagesOptionsType,\n PDFGetImagesResultType,\n PDFMetadataResultType,\n PDFOptionsType,\n PDFPageImageResultType,\n PDFRemovePagesResultType,\n PDFSplitOptionsType,\n PDFSplitResultType,\n PDFToImagesOptionsType,\n PDFUpdateMetadataOptionsType,\n} from \"./types\";\n\nexport class PDF implements IPDF {\n private readonly source: string;\n private readonly options: PDFOptionsType;\n\n /**\n * Create a new PDF instance\n * @param source - Path to PDF file\n * @param options - Options for PDF processing\n */\n constructor(source: string, options: PDFOptionsType = {}) {\n this.source = path.join(...source.split(/[/\\\\]/));\n this.options = {\n scale: options.scale ?? 3,\n ...(options.password !== undefined && { password: options.password }),\n };\n }\n\n /**\n * Create a new PDF document and save to the source path\n * @param options - Optional content and metadata options for the PDF document\n * @returns Result containing the page count\n *\n * @example\n * ```typescript\n * // Create a simple empty PDF\n * const pdf = new PDF(\"/path/to/output.pdf\");\n * const result = await pdf.create();\n *\n * // Create a PDF with metadata\n * const pdf = new PDF(\"/path/to/output.pdf\");\n * const result = await pdf.create({\n * title: \"My Document\",\n * author: \"John Doe\",\n * subject: \"Example PDF\",\n * keywords: [\"example\", \"pdf\", \"document\"],\n * creator: \"My App\",\n * producer: \"pdf-lib\",\n * });\n * ```\n */\n public async create(options: PDFCreateOptionsType = {}): Promise<PDFCreateResultType> {\n try {\n const pdfDoc = await PDFDocument.create();\n\n // Set metadata if provided\n if (options.title) {\n pdfDoc.setTitle(options.title);\n }\n if (options.author) {\n pdfDoc.setAuthor(options.author);\n }\n if (options.subject) {\n pdfDoc.setSubject(options.subject);\n }\n if (options.keywords) {\n pdfDoc.setKeywords(options.keywords);\n }\n if (options.producer) {\n pdfDoc.setProducer(options.producer);\n }\n if (options.creator) {\n pdfDoc.setCreator(options.creator);\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n\n return {\n pageCount: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to create PDF document\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Add a page to an existing PDF document\n * @param options - Optional content options for the page\n * @returns Result containing the total page count\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Add an empty page\n * await pdf.addPage();\n *\n * // Add a page with content\n * await pdf.addPage({\n * content: \"Hello, World!\",\n * fontSize: 24,\n * });\n * ```\n */\n public async addPage(options: PDFAddPageOptionsType = {}): Promise<PDFAddPageResultType> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n const page = pdfDoc.addPage();\n\n // Add content if provided\n if (options.content) {\n const font = await pdfDoc.embedFont(StandardFonts.Helvetica);\n const fontSize = options.fontSize ?? 12;\n const margin = 50;\n const lineHeight = fontSize * 1.2;\n\n const { height } = page.getSize();\n let y = height - margin;\n\n const lines = options.content.split(\"\\n\");\n\n for (const line of lines) {\n if (y < margin) {\n break;\n }\n\n page.drawText(line, {\n x: margin,\n y,\n size: fontSize,\n font,\n color: rgb(0, 0, 0),\n });\n\n y -= lineHeight;\n }\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n\n return {\n pageCount: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to add page to PDF\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get metadata from the PDF document\n * @returns PDF metadata including title, author, dates, and page count\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n * const metadata = await pdf.getMetadata();\n *\n * console.log(metadata.title);\n * console.log(metadata.author);\n * console.log(metadata.pageCount);\n * ```\n */\n public async getMetadata(): Promise<PDFMetadataResultType> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n updateMetadata: false,\n });\n\n return {\n title: pdfDoc.getTitle(),\n author: pdfDoc.getAuthor(),\n subject: pdfDoc.getSubject(),\n keywords: pdfDoc.getKeywords(),\n producer: pdfDoc.getProducer(),\n creator: pdfDoc.getCreator(),\n creationDate: pdfDoc.getCreationDate(),\n modificationDate: pdfDoc.getModificationDate(),\n pageCount: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to get PDF metadata\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Update metadata of an existing PDF document\n * @param options - Metadata options to update\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n * await pdf.updateMetadata({\n * title: \"Updated Title\",\n * author: \"New Author\",\n * subject: \"Updated Subject\",\n * keywords: [\"updated\", \"keywords\"],\n * producer: \"My App\",\n * creator: \"pdf-lib\",\n * creationDate: new Date(\"2020-01-01\"),\n * modificationDate: new Date(),\n * });\n * ```\n */\n public async updateMetadata(options: PDFUpdateMetadataOptionsType): Promise<void> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n if (options.title !== undefined) {\n pdfDoc.setTitle(options.title);\n }\n if (options.author !== undefined) {\n pdfDoc.setAuthor(options.author);\n }\n if (options.subject !== undefined) {\n pdfDoc.setSubject(options.subject);\n }\n if (options.keywords !== undefined) {\n pdfDoc.setKeywords(options.keywords);\n }\n if (options.producer !== undefined) {\n pdfDoc.setProducer(options.producer);\n }\n if (options.creator !== undefined) {\n pdfDoc.setCreator(options.creator);\n }\n if (options.creationDate !== undefined) {\n pdfDoc.setCreationDate(options.creationDate);\n }\n if (options.modificationDate !== undefined) {\n pdfDoc.setModificationDate(options.modificationDate);\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to update PDF metadata\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get the total number of pages in the PDF\n */\n public async getPageCount(): Promise<number> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n updateMetadata: false,\n });\n return pdfDoc.getPageCount();\n } catch (error) {\n throw new PDFException(\"Failed to get page count\", {\n source: this.source,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Get the text content of a specific page\n * @param pageNumber - Page number (1-indexed)\n * @returns Extracted text content from the page\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Get content from page 1\n * const content = await pdf.getPageContent(1);\n * console.log(content); // \"Lorem ipsum dolor sit amet...\"\n *\n * // Get content from a specific page\n * const page3Content = await pdf.getPageContent(3);\n * console.log(page3Content); // Plain text content\n * ```\n */\n public async getPageContent(pageNumber: number): Promise<string> {\n if (pageNumber < 1 || !Number.isInteger(pageNumber)) {\n throw new PDFException(\"Page number must be a positive integer\", {\n pageNumber,\n });\n }\n\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n const document = await getDocumentProxy(new Uint8Array(sourceBytes));\n const totalPages = document.numPages;\n\n if (pageNumber > totalPages) {\n throw new PDFException(\"Page number exceeds total pages\", {\n pageNumber,\n totalPages,\n });\n }\n\n const page = await document.getPage(pageNumber);\n const textContent = await page.getTextContent();\n const text = textContent.items\n .filter((item) => \"str\" in item)\n .map((item) => (\"hasEOL\" in item && item.hasEOL ? `${item.str}\\n` : item.str))\n .join(\"\");\n\n return text.trim();\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to get page content\", {\n source: this.source,\n pageNumber,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Extract images from PDF pages and save to disk\n * @param options - Options including output directory, optional prefix, and optional page number\n * @returns Result containing total pages and array of extracted images with file paths\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Extract images from all pages\n * const images = await pdf.getImages({ outputDir: \"/output\" });\n * console.log(`Found ${images.length} images`);\n *\n * // Extract images from a specific page\n * const page1Images = await pdf.getImages({ outputDir: \"/output\", prefix: \"doc\", pageNumber: 1 });\n * for (const image of page1Images) {\n * console.log(`Image: ${image.path}, ${image.width}x${image.height}`);\n * }\n * ```\n */\n public async getImages(options: PDFGetImagesOptionsType): Promise<PDFGetImagesResultType> {\n const { pageNumber } = options;\n\n if (pageNumber !== undefined && (pageNumber < 1 || !Number.isInteger(pageNumber))) {\n throw new PDFException(\"Page number must be a positive integer\", {\n pageNumber,\n });\n }\n\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"image\";\n\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n const document = await getDocumentProxy(new Uint8Array(sourceBytes));\n const totalPages = document.numPages;\n\n if (pageNumber !== undefined && pageNumber > totalPages) {\n throw new PDFException(\"Page number exceeds total pages\", {\n pageNumber,\n totalPages,\n });\n }\n\n const processPage = async (page: number) => {\n const pageImages = await extractImages(document, page);\n const results: PDFExtractedImageType[] = [];\n let imageIndex = 0;\n for (const img of pageImages) {\n imageIndex++;\n const fileName = `${prefix}-p${page}-${imageIndex}.png`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n // Convert raw image data to PNG using sharp\n const pngBuffer = await sharp(img.data, {\n raw: {\n width: img.width,\n height: img.height,\n channels: img.channels,\n },\n })\n .png()\n .toBuffer();\n\n await Bun.write(filePath, pngBuffer);\n\n results.push({\n page,\n path: filePath,\n width: img.width,\n height: img.height,\n });\n }\n return results;\n };\n\n if (pageNumber !== undefined) {\n return await processPage(pageNumber);\n }\n\n const allResults = await Promise.all(Array.from({ length: totalPages }, (_, i) => processPage(i + 1)));\n return allResults.flat();\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to extract images from PDF\", {\n source: this.source,\n outputDir: normalizedOutputDir,\n pageNumber,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Convert all pages to images and save to disk\n * @param options - Options including output directory and optional prefix\n * @returns Array of page image results with page numbers and file paths\n */\n public async *pagesToImages(options: PDFToImagesOptionsType): AsyncGenerator<PDFPageImageResultType, void, unknown> {\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"page\";\n const savedWorker = (globalThis as Record<string, unknown>).pdfjsWorker;\n (globalThis as Record<string, unknown>).pdfjsWorker = undefined;\n\n try {\n const document = await pdf(this.source, this.options);\n let pageNumber = 1;\n\n for await (const image of document) {\n const fileName = `${prefix}-${pageNumber}.png`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n await Bun.write(filePath, Buffer.from(image));\n\n yield {\n page: pageNumber,\n path: filePath,\n };\n pageNumber++;\n }\n\n (globalThis as Record<string, unknown>).pdfjsWorker = savedWorker;\n } catch (error) {\n (globalThis as Record<string, unknown>).pdfjsWorker = savedWorker;\n throw new PDFException(\"Failed to convert PDF to images\", {\n source: this.source,\n outputDir: normalizedOutputDir,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Convert a specific page to an image and save to disk\n * @param pageNumber - Page number (1-indexed)\n * @param options - Options including output directory and optional prefix\n * @returns Page image result with page number and file path\n */\n public async pageToImage(pageNumber: number, options: PDFToImagesOptionsType): Promise<PDFPageImageResultType> {\n if (pageNumber < 1 || !Number.isInteger(pageNumber)) {\n throw new PDFException(\"Page number must be a positive integer\", {\n pageNumber,\n });\n }\n\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"page\";\n const savedWorker = (globalThis as Record<string, unknown>).pdfjsWorker;\n (globalThis as Record<string, unknown>).pdfjsWorker = undefined;\n\n try {\n const document = await pdf(this.source, this.options);\n\n if (pageNumber > document.length) {\n throw new PDFException(\"Page number exceeds total pages\", {\n pageNumber,\n totalPages: document.length,\n });\n }\n\n const image = await document.getPage(pageNumber);\n\n const fileName = `${prefix}-${pageNumber}.png`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n await Bun.write(filePath, Buffer.from(image));\n\n (globalThis as Record<string, unknown>).pdfjsWorker = savedWorker;\n\n return {\n page: pageNumber,\n path: filePath,\n };\n } catch (error) {\n (globalThis as Record<string, unknown>).pdfjsWorker = savedWorker;\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to get page image\", {\n source: this.source,\n pageNumber,\n outputDir: normalizedOutputDir,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Split the PDF into separate documents and save to disk\n * @param options - Split options with output directory, page ranges, and optional prefix\n * @returns Array of split PDF results with page ranges and file paths\n */\n public async *split(options: PDFSplitOptionsType): AsyncGenerator<PDFSplitResultType, void, unknown> {\n const normalizedOutputDir = path.join(...options.outputDir.split(/[/\\\\]/));\n const prefix = options.prefix ?? \"page\";\n\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const sourcePdf = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n const totalPages = sourcePdf.getPageCount();\n\n if (totalPages === 0) {\n throw new PDFException(\"PDF has no pages\", {\n source: this.source,\n });\n }\n\n const ranges = this.normalizeRanges(options.ranges, totalPages);\n\n // Validate all ranges first\n for (const { start, end } of ranges) {\n if (start < 1 || end > totalPages || start > end) {\n throw new PDFException(\"Invalid page range\", {\n start,\n end,\n totalPages,\n });\n }\n }\n\n for (const { start, end } of ranges) {\n const newPdf = await PDFDocument.create();\n const pageIndices = Array.from({ length: end - start + 1 }, (_, i) => start - 1 + i);\n const copiedPages = await newPdf.copyPages(sourcePdf, pageIndices);\n\n for (const page of copiedPages) {\n newPdf.addPage(page);\n }\n\n const pdfBytes = await newPdf.save();\n\n const fileName = start === end ? `${prefix}-${start}.pdf` : `${prefix}-${start}-${end}.pdf`;\n const filePath = path.join(normalizedOutputDir, fileName);\n\n await Bun.write(filePath, pdfBytes);\n\n yield {\n pages: { start, end },\n path: filePath,\n };\n }\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to split PDF\", {\n source: this.source,\n outputDir: normalizedOutputDir,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Remove specified pages from the PDF\n * @param pages - Page numbers to remove (1-indexed). Can be individual numbers or ranges [start, end]\n * @returns Result with remaining page count and PDF buffer\n *\n * @example\n * ```typescript\n * const pdf = new PDF(\"/path/to/document.pdf\");\n *\n * // Remove individual pages (pages 2 and 5)\n * const result1 = await pdf.removePages([2, 5]);\n *\n * // Remove a range of pages (pages 3 to 6)\n * const result2 = await pdf.removePages([[3, 6]]);\n *\n * // Remove mixed: individual pages and ranges (pages 1, 4-6, and 10)\n * const result3 = await pdf.removePages([1, [4, 6], 10]);\n *\n * console.log(result3.remainingPages); // Number of pages left\n * console.log(result3.buffer); // Buffer containing the resulting PDF\n *\n * // Save to file\n * await Bun.write(\"/path/to/output.pdf\", result3.buffer);\n * ```\n */\n public async removePages(pages: (number | [number, number])[]): Promise<PDFRemovePagesResultType> {\n try {\n const sourceBytes = await Bun.file(this.source).arrayBuffer();\n\n const pdfDoc = await PDFDocument.load(sourceBytes, {\n ignoreEncryption: this.options.password !== undefined,\n });\n\n const totalPages = pdfDoc.getPageCount();\n\n if (totalPages === 0) {\n throw new PDFException(\"PDF has no pages\", {\n source: this.source,\n });\n }\n\n // Normalize page numbers to remove into a flat sorted array\n const pagesToRemove = this.normalizePageNumbers(pages, totalPages);\n\n if (pagesToRemove.length === 0) {\n throw new PDFException(\"No valid pages specified for removal\", {\n pages,\n });\n }\n\n if (pagesToRemove.length >= totalPages) {\n throw new PDFException(\"Cannot remove all pages from PDF\", {\n pagesToRemove,\n totalPages,\n });\n }\n\n // Remove pages in reverse order to maintain correct indices\n const sortedDescending = [...pagesToRemove].sort((a, b) => b - a);\n for (const pageNum of sortedDescending) {\n pdfDoc.removePage(pageNum - 1); // Convert to 0-indexed\n }\n\n const pdfBytes = await pdfDoc.save();\n\n await Bun.write(this.source, pdfBytes);\n\n return {\n remainingPages: pdfDoc.getPageCount(),\n };\n } catch (error) {\n if (error instanceof PDFException) {\n throw error;\n }\n throw new PDFException(\"Failed to remove pages from PDF\", {\n source: this.source,\n pages,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Normalize page numbers into a flat array of unique valid page numbers\n */\n private normalizePageNumbers(pages: (number | [number, number])[], totalPages: number): number[] {\n const pageSet = new Set<number>();\n\n for (const page of pages) {\n if (typeof page === \"number\") {\n if (page >= 1 && page <= totalPages && Number.isInteger(page)) {\n pageSet.add(page);\n }\n } else {\n const [start, end] = page;\n if (start <= end) {\n for (let i = Math.max(1, start); i <= Math.min(totalPages, end); i++) {\n if (Number.isInteger(i)) {\n pageSet.add(i);\n }\n }\n }\n }\n }\n\n return Array.from(pageSet);\n }\n\n /**\n * Normalize page ranges for splitting\n * If no ranges provided, creates individual page ranges\n */\n private normalizeRanges(\n ranges: PDFSplitOptionsType[\"ranges\"] | undefined,\n totalPages: number,\n ): { start: number; end: number }[] {\n if (!ranges || ranges.length === 0) {\n return Array.from({ length: totalPages }, (_, i) => ({\n start: i + 1,\n end: i + 1,\n }));\n }\n\n return ranges.map((range) => {\n if (typeof range === \"number\") {\n return { start: range, end: range };\n }\n return { start: range[0], end: range[1] };\n });\n }\n}\n",
|
|
6
6
|
"import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class PDFException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"PDFException\";\n }\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";AAAA,oBACA,sBAAS,SAAa,mBAAK,gBAC3B,cAAS,mBACT,qBACA,wBAAS,
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "D77D34577E7BB37C64756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ooneex/pdf",
|
|
3
|
-
"description": "PDF
|
|
4
|
-
"version": "0.0
|
|
3
|
+
"description": "PDF document toolkit for generating, editing, merging, splitting, and converting PDF files to images with page-level content extraction",
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"npm:publish": "bun publish --tolerate-republish --access public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@ooneex/exception": "0.0.
|
|
32
|
-
"@ooneex/http-status": "0.0.
|
|
31
|
+
"@ooneex/exception": "0.0.18",
|
|
32
|
+
"@ooneex/http-status": "0.0.18",
|
|
33
33
|
"pdf-lib": "^1.17.1",
|
|
34
34
|
"pdf-to-img": "^5.0.0",
|
|
35
35
|
"sharp": "^0.33.5",
|
|
36
|
-
"unpdf": "^
|
|
36
|
+
"unpdf": "^1.4.0"
|
|
37
37
|
},
|
|
38
38
|
"keywords": [
|
|
39
39
|
"bun",
|