pdf-oxide-fips 0.3.47
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-APACHE +176 -0
- package/LICENSE-MIT +25 -0
- package/README.md +218 -0
- package/lib/builders/annotation-builder.d.ts +198 -0
- package/lib/builders/annotation-builder.js +317 -0
- package/lib/builders/conversion-options-builder.d.ts +106 -0
- package/lib/builders/conversion-options-builder.js +214 -0
- package/lib/builders/document-builder.d.ts +381 -0
- package/lib/builders/document-builder.js +770 -0
- package/lib/builders/index.d.ts +13 -0
- package/lib/builders/index.js +13 -0
- package/lib/builders/metadata-builder.d.ts +201 -0
- package/lib/builders/metadata-builder.js +285 -0
- package/lib/builders/pdf-builder.d.ts +216 -0
- package/lib/builders/pdf-builder.js +350 -0
- package/lib/builders/search-options-builder.d.ts +73 -0
- package/lib/builders/search-options-builder.js +129 -0
- package/lib/builders/streaming-table.d.ts +64 -0
- package/lib/builders/streaming-table.js +140 -0
- package/lib/document-editor-manager.d.ts +139 -0
- package/lib/document-editor-manager.js +256 -0
- package/lib/document-editor.d.ts +124 -0
- package/lib/document-editor.js +318 -0
- package/lib/errors.d.ts +382 -0
- package/lib/errors.js +1115 -0
- package/lib/form-field-manager.d.ts +299 -0
- package/lib/form-field-manager.js +568 -0
- package/lib/hybrid-ml-manager.d.ts +142 -0
- package/lib/hybrid-ml-manager.js +208 -0
- package/lib/index.d.ts +205 -0
- package/lib/index.js +693 -0
- package/lib/managers/accessibility-manager.d.ts +148 -0
- package/lib/managers/accessibility-manager.js +234 -0
- package/lib/managers/annotation-manager.d.ts +219 -0
- package/lib/managers/annotation-manager.js +359 -0
- package/lib/managers/barcode-manager.d.ts +82 -0
- package/lib/managers/barcode-manager.js +263 -0
- package/lib/managers/batch-manager.d.ts +185 -0
- package/lib/managers/batch-manager.js +385 -0
- package/lib/managers/cache-manager.d.ts +181 -0
- package/lib/managers/cache-manager.js +384 -0
- package/lib/managers/compliance-manager.d.ts +103 -0
- package/lib/managers/compliance-manager.js +453 -0
- package/lib/managers/content-manager.d.ts +120 -0
- package/lib/managers/content-manager.js +294 -0
- package/lib/managers/document-utility-manager.d.ts +369 -0
- package/lib/managers/document-utility-manager.js +730 -0
- package/lib/managers/dom-pdf-creator.d.ts +104 -0
- package/lib/managers/dom-pdf-creator.js +299 -0
- package/lib/managers/editing-manager.d.ts +248 -0
- package/lib/managers/editing-manager.js +387 -0
- package/lib/managers/enterprise-manager.d.ts +192 -0
- package/lib/managers/enterprise-manager.js +307 -0
- package/lib/managers/extended-managers.d.ts +122 -0
- package/lib/managers/extended-managers.js +664 -0
- package/lib/managers/extraction-manager.d.ts +246 -0
- package/lib/managers/extraction-manager.js +482 -0
- package/lib/managers/final-utilities.d.ts +127 -0
- package/lib/managers/final-utilities.js +657 -0
- package/lib/managers/hybrid-ml-advanced.d.ts +136 -0
- package/lib/managers/hybrid-ml-advanced.js +722 -0
- package/lib/managers/index.d.ts +64 -0
- package/lib/managers/index.js +69 -0
- package/lib/managers/layer-manager.d.ts +203 -0
- package/lib/managers/layer-manager.js +401 -0
- package/lib/managers/metadata-manager.d.ts +148 -0
- package/lib/managers/metadata-manager.js +280 -0
- package/lib/managers/ocr-manager.d.ts +194 -0
- package/lib/managers/ocr-manager.js +582 -0
- package/lib/managers/optimization-manager.d.ts +102 -0
- package/lib/managers/optimization-manager.js +213 -0
- package/lib/managers/outline-manager.d.ts +101 -0
- package/lib/managers/outline-manager.js +169 -0
- package/lib/managers/page-manager.d.ts +142 -0
- package/lib/managers/page-manager.js +235 -0
- package/lib/managers/pattern-detection.d.ts +169 -0
- package/lib/managers/pattern-detection.js +322 -0
- package/lib/managers/rendering-manager.d.ts +353 -0
- package/lib/managers/rendering-manager.js +679 -0
- package/lib/managers/search-manager.d.ts +235 -0
- package/lib/managers/search-manager.js +329 -0
- package/lib/managers/security-manager.d.ts +161 -0
- package/lib/managers/security-manager.js +292 -0
- package/lib/managers/signature-manager.d.ts +738 -0
- package/lib/managers/signature-manager.js +1509 -0
- package/lib/managers/streams.d.ts +262 -0
- package/lib/managers/streams.js +477 -0
- package/lib/managers/xfa-manager.d.ts +227 -0
- package/lib/managers/xfa-manager.js +539 -0
- package/lib/native-loader.d.ts +7 -0
- package/lib/native-loader.js +62 -0
- package/lib/native.d.ts +16 -0
- package/lib/native.js +69 -0
- package/lib/pdf-creator-manager.d.ts +200 -0
- package/lib/pdf-creator-manager.js +381 -0
- package/lib/properties.d.ts +79 -0
- package/lib/properties.js +454 -0
- package/lib/result-accessors-manager.d.ts +346 -0
- package/lib/result-accessors-manager.js +706 -0
- package/lib/thumbnail-manager.d.ts +121 -0
- package/lib/thumbnail-manager.js +205 -0
- package/lib/timestamp.d.ts +54 -0
- package/lib/timestamp.js +115 -0
- package/lib/tsa-client.d.ts +44 -0
- package/lib/tsa-client.js +67 -0
- package/lib/types/common.d.ts +189 -0
- package/lib/types/common.js +17 -0
- package/lib/types/document-types.d.ts +352 -0
- package/lib/types/document-types.js +82 -0
- package/lib/types/index.d.ts +5 -0
- package/lib/types/index.js +5 -0
- package/lib/types/manager-types.d.ts +179 -0
- package/lib/types/manager-types.js +100 -0
- package/lib/types/native-bindings.d.ts +439 -0
- package/lib/types/native-bindings.js +7 -0
- package/lib/workers/index.d.ts +6 -0
- package/lib/workers/index.js +5 -0
- package/lib/workers/pool.d.ts +64 -0
- package/lib/workers/pool.js +192 -0
- package/lib/workers/worker.d.ts +5 -0
- package/lib/workers/worker.js +99 -0
- package/package.json +79 -0
- package/prebuilds/darwin-arm64/pdf_oxide.node +0 -0
- package/prebuilds/darwin-x64/pdf_oxide.node +0 -0
- package/prebuilds/linux-arm64/pdf_oxide.node +0 -0
- package/prebuilds/linux-x64/pdf_oxide.node +0 -0
- package/prebuilds/win32-x64/pdf_oxide.node +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEditorManager for PDF document editing operations
|
|
3
|
+
*
|
|
4
|
+
* Provides methods to edit and modify PDF documents including page operations,
|
|
5
|
+
* content manipulation, and document merging. API is consistent with Python,
|
|
6
|
+
* Java, C#, Go, and Swift implementations.
|
|
7
|
+
*/
|
|
8
|
+
import { EventEmitter } from 'events';
|
|
9
|
+
/**
|
|
10
|
+
* Page rotation options
|
|
11
|
+
*/
|
|
12
|
+
export var PageRotation;
|
|
13
|
+
(function (PageRotation) {
|
|
14
|
+
PageRotation[PageRotation["None"] = 0] = "None";
|
|
15
|
+
PageRotation[PageRotation["Rotate90"] = 90] = "Rotate90";
|
|
16
|
+
PageRotation[PageRotation["Rotate180"] = 180] = "Rotate180";
|
|
17
|
+
PageRotation[PageRotation["Rotate270"] = 270] = "Rotate270";
|
|
18
|
+
})(PageRotation || (PageRotation = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Document Editor Manager for document manipulation
|
|
21
|
+
*
|
|
22
|
+
* Provides methods to:
|
|
23
|
+
* - Delete, insert, and reorder pages
|
|
24
|
+
* - Rotate pages
|
|
25
|
+
* - Extract page ranges to new documents
|
|
26
|
+
* - Merge multiple documents
|
|
27
|
+
* - Track edit history
|
|
28
|
+
*/
|
|
29
|
+
export class DocumentEditorManager extends EventEmitter {
|
|
30
|
+
constructor(document) {
|
|
31
|
+
super();
|
|
32
|
+
this.editHistory = [];
|
|
33
|
+
this.hasUnsavedChanges = false;
|
|
34
|
+
if (!document) {
|
|
35
|
+
throw new Error('Document is required');
|
|
36
|
+
}
|
|
37
|
+
this.document = document;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Deletes a page from the document
|
|
41
|
+
* Matches: Python deletePage(), Java deletePage(), C# DeletePage()
|
|
42
|
+
*/
|
|
43
|
+
async deletePage(pageIndex) {
|
|
44
|
+
this.validatePageIndex(pageIndex);
|
|
45
|
+
try {
|
|
46
|
+
if (this.document?.removePage) {
|
|
47
|
+
this.document.removePage(pageIndex);
|
|
48
|
+
}
|
|
49
|
+
this.recordOperation('deletePage', { pageIndex });
|
|
50
|
+
this.emit('pageDeleted', pageIndex);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
this.emit('error', error);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Deletes multiple pages from the document
|
|
59
|
+
* Matches: Python deletePages(), Java deletePages(), C# DeletePages()
|
|
60
|
+
*/
|
|
61
|
+
async deletePages(pageIndices) {
|
|
62
|
+
// Sort in descending order to avoid index shifting issues
|
|
63
|
+
const sorted = [...pageIndices].sort((a, b) => b - a);
|
|
64
|
+
for (const pageIndex of sorted) {
|
|
65
|
+
await this.deletePage(pageIndex);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Inserts a blank page at the specified position
|
|
70
|
+
* Matches: Python insertBlankPage(), Java insertBlankPage(), C# InsertBlankPage()
|
|
71
|
+
*/
|
|
72
|
+
async insertBlankPage(pageIndex, width = 612, height = 792) {
|
|
73
|
+
try {
|
|
74
|
+
if (this.document?.insertPage) {
|
|
75
|
+
this.document.insertPage(pageIndex, width, height);
|
|
76
|
+
}
|
|
77
|
+
this.recordOperation('insertBlankPage', { pageIndex, width, height });
|
|
78
|
+
this.emit('pageInserted', pageIndex);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
this.emit('error', error);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Rotates a page by the specified angle
|
|
87
|
+
* Matches: Python rotatePage(), Java rotatePage(), C# RotatePage()
|
|
88
|
+
*/
|
|
89
|
+
async rotatePage(pageIndex, rotation) {
|
|
90
|
+
this.validatePageIndex(pageIndex);
|
|
91
|
+
try {
|
|
92
|
+
if (this.document?.rotatePage) {
|
|
93
|
+
this.document.rotatePage(pageIndex, rotation);
|
|
94
|
+
}
|
|
95
|
+
this.recordOperation('rotatePage', { pageIndex, rotation });
|
|
96
|
+
this.emit('pageRotated', pageIndex, rotation);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
this.emit('error', error);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Rotates multiple pages
|
|
105
|
+
* Matches: Python rotatePages(), Java rotatePages(), C# RotatePages()
|
|
106
|
+
*/
|
|
107
|
+
async rotatePages(pageIndices, rotation) {
|
|
108
|
+
for (const pageIndex of pageIndices) {
|
|
109
|
+
await this.rotatePage(pageIndex, rotation);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Moves a page to a new position
|
|
114
|
+
* Matches: Python movePage(), Java movePage(), C# MovePage()
|
|
115
|
+
*/
|
|
116
|
+
async movePage(fromIndex, toIndex) {
|
|
117
|
+
this.validatePageIndex(fromIndex);
|
|
118
|
+
this.validatePageIndex(toIndex);
|
|
119
|
+
try {
|
|
120
|
+
// Implement move by extracting and re-inserting
|
|
121
|
+
if (this.document?.getPage && this.document?.removePage && this.document?.insertPage) {
|
|
122
|
+
const page = this.document.getPage(fromIndex);
|
|
123
|
+
this.document.removePage(fromIndex);
|
|
124
|
+
// Note: After removal, toIndex may need adjustment
|
|
125
|
+
const adjustedIndex = toIndex > fromIndex ? toIndex - 1 : toIndex;
|
|
126
|
+
if (page) {
|
|
127
|
+
this.document.insertPage(adjustedIndex, page.getWidth?.(), page.getHeight?.());
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
this.recordOperation('movePage', { fromIndex, toIndex });
|
|
131
|
+
this.emit('pageMoved', fromIndex, toIndex);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
this.emit('error', error);
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Extracts pages to a new document
|
|
140
|
+
* Matches: Python extractPages(), Java extractPages(), C# ExtractPages()
|
|
141
|
+
*/
|
|
142
|
+
async extractPages(config) {
|
|
143
|
+
const { startPage, endPage } = config;
|
|
144
|
+
this.validatePageIndex(startPage);
|
|
145
|
+
this.validatePageIndex(endPage);
|
|
146
|
+
// FFI call placeholder
|
|
147
|
+
// const newDoc = await FFI.extractPages(this.document.handle, startPage, endPage);
|
|
148
|
+
this.recordOperation('extractPages', { startPage, endPage });
|
|
149
|
+
this.emit('pagesExtracted', startPage, endPage);
|
|
150
|
+
return null; // Placeholder - would return new document
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Merges multiple documents into one
|
|
154
|
+
* Matches: Python mergeDocuments(), Java mergeDocuments(), C# MergeDocuments()
|
|
155
|
+
*/
|
|
156
|
+
static async mergeDocuments(config) {
|
|
157
|
+
const { documents, preserveOutlines = true, preserveAnnotations = true } = config;
|
|
158
|
+
if (!documents || documents.length === 0) {
|
|
159
|
+
throw new Error('At least one document is required for merging');
|
|
160
|
+
}
|
|
161
|
+
// FFI call placeholder
|
|
162
|
+
// const merged = await FFI.mergeDocuments(documents, preserveOutlines, preserveAnnotations);
|
|
163
|
+
return null; // Placeholder - would return merged document
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Saves the document with all modifications
|
|
167
|
+
* Matches: Python save(), Java save(), C# Save()
|
|
168
|
+
*/
|
|
169
|
+
async save(outputPath) {
|
|
170
|
+
try {
|
|
171
|
+
if (outputPath) {
|
|
172
|
+
// Save to file path
|
|
173
|
+
if (this.document?.save_async) {
|
|
174
|
+
await this.document.save_async(outputPath);
|
|
175
|
+
}
|
|
176
|
+
else if (this.document?.saveToPath) {
|
|
177
|
+
this.document.saveToPath(outputPath);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
// Save changes to current document
|
|
182
|
+
if (this.document?.save_async) {
|
|
183
|
+
await this.document.save_async(this.document.filePath || 'output.pdf');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
this.hasUnsavedChanges = false;
|
|
187
|
+
this.emit('saved', outputPath);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
this.emit('error', error);
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Gets the edit history
|
|
196
|
+
* Matches: Python getEditHistory(), Java getEditHistory(), C# GetEditHistory()
|
|
197
|
+
*/
|
|
198
|
+
getEditHistory() {
|
|
199
|
+
return [...this.editHistory];
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Checks if there are unsaved changes
|
|
203
|
+
* Matches: Python hasUnsavedChanges(), Java hasUnsavedChanges(), C# HasUnsavedChanges()
|
|
204
|
+
*/
|
|
205
|
+
hasChanges() {
|
|
206
|
+
return this.hasUnsavedChanges;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Undoes the last operation (if supported)
|
|
210
|
+
* Matches: Python undo(), Java undo(), C# Undo()
|
|
211
|
+
*/
|
|
212
|
+
async undo() {
|
|
213
|
+
if (this.editHistory.length === 0) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
// Placeholder - would implement undo logic
|
|
217
|
+
this.editHistory.pop();
|
|
218
|
+
this.emit('undone');
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Clears the edit history
|
|
223
|
+
* Matches: Python clearHistory(), Java clearHistory(), C# ClearHistory()
|
|
224
|
+
*/
|
|
225
|
+
clearHistory() {
|
|
226
|
+
this.editHistory = [];
|
|
227
|
+
this.emit('historyCleared');
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Gets the page count after modifications
|
|
231
|
+
*/
|
|
232
|
+
getPageCount() {
|
|
233
|
+
try {
|
|
234
|
+
return this.document.pageCount || 0;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Private helper methods
|
|
241
|
+
validatePageIndex(pageIndex) {
|
|
242
|
+
const count = this.getPageCount();
|
|
243
|
+
if (pageIndex < 0 || pageIndex >= count) {
|
|
244
|
+
throw new Error(`Invalid page index: ${pageIndex}. Document has ${count} pages.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
recordOperation(type, details) {
|
|
248
|
+
this.editHistory.push({
|
|
249
|
+
type,
|
|
250
|
+
timestamp: new Date(),
|
|
251
|
+
details,
|
|
252
|
+
});
|
|
253
|
+
this.hasUnsavedChanges = true;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
export default DocumentEditorManager;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page rotation angles valid for {@link DocumentEditor.setPageRotation}.
|
|
3
|
+
*/
|
|
4
|
+
export type PageRotation = 0 | 90 | 180 | 270;
|
|
5
|
+
/**
|
|
6
|
+
* PDF editor bound to a concrete file on disk. Open via
|
|
7
|
+
* {@link DocumentEditor.open}; always pair with {@link close} (or use
|
|
8
|
+
* `using` / the explicit-resource-management protocol once it's
|
|
9
|
+
* stable in your toolchain).
|
|
10
|
+
*/
|
|
11
|
+
export declare class DocumentEditor {
|
|
12
|
+
private _handle;
|
|
13
|
+
private _closed;
|
|
14
|
+
private constructor();
|
|
15
|
+
/** Open a PDF file for editing. */
|
|
16
|
+
static open(path: string): DocumentEditor;
|
|
17
|
+
/** Open a PDF from an in-memory buffer for editing. */
|
|
18
|
+
static openFromBytes(data: Buffer | Uint8Array): DocumentEditor;
|
|
19
|
+
/** True if the editor has been closed. Subsequent calls will throw. */
|
|
20
|
+
get closed(): boolean;
|
|
21
|
+
private _throwIfClosed;
|
|
22
|
+
/** Current page count. */
|
|
23
|
+
pageCount(): number;
|
|
24
|
+
/** True if the editor has unsaved modifications. */
|
|
25
|
+
isModified(): boolean;
|
|
26
|
+
setTitle(title: string): void;
|
|
27
|
+
setAuthor(author: string): void;
|
|
28
|
+
setSubject(subject: string): void;
|
|
29
|
+
getKeywords(): string | null;
|
|
30
|
+
setKeywords(keywords: string): void;
|
|
31
|
+
getProducer(): string;
|
|
32
|
+
setProducer(producer: string): void;
|
|
33
|
+
getCreationDate(): string;
|
|
34
|
+
setCreationDate(date: string): void;
|
|
35
|
+
/** Delete the page at `pageIndex` (zero-based). */
|
|
36
|
+
deletePage(pageIndex: number): void;
|
|
37
|
+
/** Move a page. Indices refer to positions before the move. */
|
|
38
|
+
movePage(fromIndex: number, toIndex: number): void;
|
|
39
|
+
/** Set rotation on a page (0/90/180/270). */
|
|
40
|
+
setPageRotation(pageIndex: number, degrees: PageRotation): void;
|
|
41
|
+
/**
|
|
42
|
+
* Append every page of another PDF to the end of this document.
|
|
43
|
+
*/
|
|
44
|
+
mergeFrom(sourcePath: string): void;
|
|
45
|
+
/** Flatten form fields across the entire document. */
|
|
46
|
+
flattenForms(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Return warnings collected during the last form-flattening save.
|
|
49
|
+
* Each entry names a widget field that had no `/AP` appearance stream;
|
|
50
|
+
* flattening it produces a blank rectangle.
|
|
51
|
+
*/
|
|
52
|
+
flattenWarnings(): string[];
|
|
53
|
+
/** Flatten annotations. If `pageIndex` is omitted, flattens all pages. */
|
|
54
|
+
flattenAnnotations(pageIndex?: number): void;
|
|
55
|
+
/** Set a form field value by fully-qualified field name. */
|
|
56
|
+
setFormFieldValue(fieldName: string, value: string): void;
|
|
57
|
+
/** Import an FDF file (bytes) into the document's form. */
|
|
58
|
+
importFdfBytes(fdf: Buffer | Uint8Array): void;
|
|
59
|
+
/** Import an XFDF file (bytes) into the document's form. */
|
|
60
|
+
importXfdfBytes(xfdf: Buffer | Uint8Array): void;
|
|
61
|
+
/**
|
|
62
|
+
* Append every page of another PDF (supplied as bytes) to this document.
|
|
63
|
+
* Returns the number of pages added.
|
|
64
|
+
*/
|
|
65
|
+
mergeFromBytes(data: Buffer | Uint8Array): number;
|
|
66
|
+
/** Embed a file attachment into the document. */
|
|
67
|
+
embedFile(name: string, data: Buffer | Uint8Array): void;
|
|
68
|
+
/** Burn in redaction annotations on a single page (zero-based). */
|
|
69
|
+
applyPageRedactions(pageIndex: number): void;
|
|
70
|
+
/** Burn in all pending redaction annotations across the document. */
|
|
71
|
+
applyAllRedactions(): void;
|
|
72
|
+
/** Rotate all pages by `degrees` (additive). */
|
|
73
|
+
rotateAllPages(degrees: number): void;
|
|
74
|
+
/** Rotate a single page by `degrees` (additive). */
|
|
75
|
+
rotatePageBy(pageIndex: number, degrees: number): void;
|
|
76
|
+
/** Get the MediaBox of a page as `{x, y, width, height}`. */
|
|
77
|
+
getPageMediaBox(pageIndex: number): {
|
|
78
|
+
x: number;
|
|
79
|
+
y: number;
|
|
80
|
+
width: number;
|
|
81
|
+
height: number;
|
|
82
|
+
};
|
|
83
|
+
/** Set the MediaBox of a page. */
|
|
84
|
+
setPageMediaBox(pageIndex: number, x: number, y: number, width: number, height: number): void;
|
|
85
|
+
/** Get the CropBox of a page. Returns `{x:0,y:0,width:0,height:0}` if none set. */
|
|
86
|
+
getPageCropBox(pageIndex: number): {
|
|
87
|
+
x: number;
|
|
88
|
+
y: number;
|
|
89
|
+
width: number;
|
|
90
|
+
height: number;
|
|
91
|
+
};
|
|
92
|
+
/** Set the CropBox of a page. */
|
|
93
|
+
setPageCropBox(pageIndex: number, x: number, y: number, width: number, height: number): void;
|
|
94
|
+
/**
|
|
95
|
+
* Erase rectangular regions on a page.
|
|
96
|
+
* `rects` is an array of `[x, y, w, h]` tuples.
|
|
97
|
+
*/
|
|
98
|
+
eraseRegions(pageIndex: number, rects: [number, number, number, number][]): void;
|
|
99
|
+
/** Clear all pending erase-region entries for a page. */
|
|
100
|
+
clearEraseRegions(pageIndex: number): void;
|
|
101
|
+
/** Flatten form fields on a single page. */
|
|
102
|
+
flattenFormsOnPage(pageIndex: number): void;
|
|
103
|
+
/** True if the page is marked for annotation-flatten. */
|
|
104
|
+
isPageMarkedForFlatten(pageIndex: number): boolean;
|
|
105
|
+
/** Remove the flatten mark from a page. */
|
|
106
|
+
unmarkPageForFlatten(pageIndex: number): void;
|
|
107
|
+
/** True if the page is marked for redaction. */
|
|
108
|
+
isPageMarkedForRedaction(pageIndex: number): boolean;
|
|
109
|
+
/** Remove the redaction mark from a page. */
|
|
110
|
+
unmarkPageForRedaction(pageIndex: number): void;
|
|
111
|
+
/** Save the document to `path`. */
|
|
112
|
+
save(path: string): void;
|
|
113
|
+
/** Save with AES-256 encryption (user + owner passwords). */
|
|
114
|
+
saveEncrypted(path: string, userPassword: string, ownerPassword: string): void;
|
|
115
|
+
/** Extract specific pages (by 0-based index) into a new PDF returned as a Buffer. */
|
|
116
|
+
extractPagesToBytes(pageIndices: number[]): Buffer;
|
|
117
|
+
/** Save the document to an in-memory Buffer. */
|
|
118
|
+
saveToBytes(): Buffer;
|
|
119
|
+
/** Save to an in-memory Buffer with explicit compression / GC / linearize flags. */
|
|
120
|
+
saveToBytesWithOptions(compress: boolean, garbageCollect: boolean, linearize: boolean): Buffer;
|
|
121
|
+
/** Release the native handle. Safe to call multiple times. */
|
|
122
|
+
close(): void;
|
|
123
|
+
}
|
|
124
|
+
export default DocumentEditor;
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEditor — thin TS wrapper around the N-API `editor*` exports
|
|
3
|
+
* in `binding.cc`. Mirrors the C# `DocumentEditor` / Go
|
|
4
|
+
* `DocumentEditor` surface.
|
|
5
|
+
*
|
|
6
|
+
* Every mutation is a synchronous call into the Rust core; the same
|
|
7
|
+
* handle is carried until {@link DocumentEditor.close}. Throws plain
|
|
8
|
+
* `Error` with the native message on failure.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { DocumentEditor } from 'pdf-oxide';
|
|
12
|
+
*
|
|
13
|
+
* const editor = DocumentEditor.open('in.pdf');
|
|
14
|
+
* try {
|
|
15
|
+
* editor.mergeFrom('other.pdf');
|
|
16
|
+
* editor.deletePage(0);
|
|
17
|
+
* editor.movePage(0, 2);
|
|
18
|
+
* editor.setPageRotation(0, 90);
|
|
19
|
+
* editor.save('out.pdf');
|
|
20
|
+
* } finally {
|
|
21
|
+
* editor.close();
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
// Load the native addon via the shared prebuild-aware loader.
|
|
26
|
+
// Importing `./index.js` would create an ESM cycle (index.js imports
|
|
27
|
+
// us back), so we go through `./native.js` — same resolver, no cycle,
|
|
28
|
+
// resolves against `prebuilds/<triple>/pdf_oxide.node` in the
|
|
29
|
+
// published package.
|
|
30
|
+
import { loadNative } from './native.js';
|
|
31
|
+
const native = loadNative();
|
|
32
|
+
/**
|
|
33
|
+
* PDF editor bound to a concrete file on disk. Open via
|
|
34
|
+
* {@link DocumentEditor.open}; always pair with {@link close} (or use
|
|
35
|
+
* `using` / the explicit-resource-management protocol once it's
|
|
36
|
+
* stable in your toolchain).
|
|
37
|
+
*/
|
|
38
|
+
export class DocumentEditor {
|
|
39
|
+
constructor(handle) {
|
|
40
|
+
this._closed = false;
|
|
41
|
+
this._handle = handle;
|
|
42
|
+
}
|
|
43
|
+
/** Open a PDF file for editing. */
|
|
44
|
+
static open(path) {
|
|
45
|
+
if (typeof path !== 'string' || path.length === 0) {
|
|
46
|
+
throw new TypeError('path must be a non-empty string');
|
|
47
|
+
}
|
|
48
|
+
const handle = native.editorOpen(path);
|
|
49
|
+
return new DocumentEditor(handle);
|
|
50
|
+
}
|
|
51
|
+
/** Open a PDF from an in-memory buffer for editing. */
|
|
52
|
+
static openFromBytes(data) {
|
|
53
|
+
if (!data || data.length === 0) {
|
|
54
|
+
throw new TypeError('data must be a non-empty Buffer or Uint8Array');
|
|
55
|
+
}
|
|
56
|
+
const handle = native.editorOpenFromBytes(data);
|
|
57
|
+
return new DocumentEditor(handle);
|
|
58
|
+
}
|
|
59
|
+
/** True if the editor has been closed. Subsequent calls will throw. */
|
|
60
|
+
get closed() {
|
|
61
|
+
return this._closed;
|
|
62
|
+
}
|
|
63
|
+
_throwIfClosed() {
|
|
64
|
+
if (this._closed)
|
|
65
|
+
throw new Error('DocumentEditor is closed');
|
|
66
|
+
}
|
|
67
|
+
/** Current page count. */
|
|
68
|
+
pageCount() {
|
|
69
|
+
this._throwIfClosed();
|
|
70
|
+
return native.editorGetPageCount(this._handle);
|
|
71
|
+
}
|
|
72
|
+
/** True if the editor has unsaved modifications. */
|
|
73
|
+
isModified() {
|
|
74
|
+
this._throwIfClosed();
|
|
75
|
+
return native.editorIsModified(this._handle);
|
|
76
|
+
}
|
|
77
|
+
// ----- metadata ---------------------------------------------------
|
|
78
|
+
setTitle(title) {
|
|
79
|
+
this._throwIfClosed();
|
|
80
|
+
native.editorSetTitle(this._handle, title);
|
|
81
|
+
}
|
|
82
|
+
setAuthor(author) {
|
|
83
|
+
this._throwIfClosed();
|
|
84
|
+
native.editorSetAuthor(this._handle, author);
|
|
85
|
+
}
|
|
86
|
+
setSubject(subject) {
|
|
87
|
+
this._throwIfClosed();
|
|
88
|
+
native.editorSetSubject(this._handle, subject);
|
|
89
|
+
}
|
|
90
|
+
getKeywords() {
|
|
91
|
+
this._throwIfClosed();
|
|
92
|
+
return native.editorGetKeywords(this._handle);
|
|
93
|
+
}
|
|
94
|
+
setKeywords(keywords) {
|
|
95
|
+
this._throwIfClosed();
|
|
96
|
+
native.editorSetKeywords(this._handle, keywords);
|
|
97
|
+
}
|
|
98
|
+
getProducer() {
|
|
99
|
+
this._throwIfClosed();
|
|
100
|
+
return native.editorGetProducer(this._handle);
|
|
101
|
+
}
|
|
102
|
+
setProducer(producer) {
|
|
103
|
+
this._throwIfClosed();
|
|
104
|
+
native.editorSetProducer(this._handle, producer);
|
|
105
|
+
}
|
|
106
|
+
getCreationDate() {
|
|
107
|
+
this._throwIfClosed();
|
|
108
|
+
return native.editorGetCreationDate(this._handle);
|
|
109
|
+
}
|
|
110
|
+
setCreationDate(date) {
|
|
111
|
+
this._throwIfClosed();
|
|
112
|
+
native.editorSetCreationDate(this._handle, date);
|
|
113
|
+
}
|
|
114
|
+
// ----- page mutations ---------------------------------------------
|
|
115
|
+
/** Delete the page at `pageIndex` (zero-based). */
|
|
116
|
+
deletePage(pageIndex) {
|
|
117
|
+
this._throwIfClosed();
|
|
118
|
+
native.editorDeletePage(this._handle, pageIndex);
|
|
119
|
+
}
|
|
120
|
+
/** Move a page. Indices refer to positions before the move. */
|
|
121
|
+
movePage(fromIndex, toIndex) {
|
|
122
|
+
this._throwIfClosed();
|
|
123
|
+
native.editorMovePage(this._handle, fromIndex, toIndex);
|
|
124
|
+
}
|
|
125
|
+
/** Set rotation on a page (0/90/180/270). */
|
|
126
|
+
setPageRotation(pageIndex, degrees) {
|
|
127
|
+
this._throwIfClosed();
|
|
128
|
+
native.editorSetPageRotation(this._handle, pageIndex, degrees);
|
|
129
|
+
}
|
|
130
|
+
// ----- document-level mutations -----------------------------------
|
|
131
|
+
/**
|
|
132
|
+
* Append every page of another PDF to the end of this document.
|
|
133
|
+
*/
|
|
134
|
+
mergeFrom(sourcePath) {
|
|
135
|
+
this._throwIfClosed();
|
|
136
|
+
if (typeof sourcePath !== 'string' || sourcePath.length === 0) {
|
|
137
|
+
throw new TypeError('sourcePath must be a non-empty string');
|
|
138
|
+
}
|
|
139
|
+
native.editorMergeFrom(this._handle, sourcePath);
|
|
140
|
+
}
|
|
141
|
+
/** Flatten form fields across the entire document. */
|
|
142
|
+
flattenForms() {
|
|
143
|
+
this._throwIfClosed();
|
|
144
|
+
native.editorFlattenForms(this._handle);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Return warnings collected during the last form-flattening save.
|
|
148
|
+
* Each entry names a widget field that had no `/AP` appearance stream;
|
|
149
|
+
* flattening it produces a blank rectangle.
|
|
150
|
+
*/
|
|
151
|
+
flattenWarnings() {
|
|
152
|
+
this._throwIfClosed();
|
|
153
|
+
return native.editorFlattenWarnings(this._handle);
|
|
154
|
+
}
|
|
155
|
+
/** Flatten annotations. If `pageIndex` is omitted, flattens all pages. */
|
|
156
|
+
flattenAnnotations(pageIndex) {
|
|
157
|
+
this._throwIfClosed();
|
|
158
|
+
if (pageIndex === undefined) {
|
|
159
|
+
native.editorFlattenAnnotations(this._handle);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
native.editorFlattenAnnotations(this._handle, pageIndex);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** Set a form field value by fully-qualified field name. */
|
|
166
|
+
setFormFieldValue(fieldName, value) {
|
|
167
|
+
this._throwIfClosed();
|
|
168
|
+
native.editorSetFormFieldValue(this._handle, fieldName, value);
|
|
169
|
+
}
|
|
170
|
+
/** Import an FDF file (bytes) into the document's form. */
|
|
171
|
+
importFdfBytes(fdf) {
|
|
172
|
+
this._throwIfClosed();
|
|
173
|
+
native.editorImportFdfBytes(this._handle, fdf);
|
|
174
|
+
}
|
|
175
|
+
/** Import an XFDF file (bytes) into the document's form. */
|
|
176
|
+
importXfdfBytes(xfdf) {
|
|
177
|
+
this._throwIfClosed();
|
|
178
|
+
native.editorImportXfdfBytes(this._handle, xfdf);
|
|
179
|
+
}
|
|
180
|
+
// ----- byte-level merge / embed -----------------------------------
|
|
181
|
+
/**
|
|
182
|
+
* Append every page of another PDF (supplied as bytes) to this document.
|
|
183
|
+
* Returns the number of pages added.
|
|
184
|
+
*/
|
|
185
|
+
mergeFromBytes(data) {
|
|
186
|
+
this._throwIfClosed();
|
|
187
|
+
return native.editorMergeFromBytes(this._handle, data);
|
|
188
|
+
}
|
|
189
|
+
/** Embed a file attachment into the document. */
|
|
190
|
+
embedFile(name, data) {
|
|
191
|
+
this._throwIfClosed();
|
|
192
|
+
native.editorEmbedFile(this._handle, name, data);
|
|
193
|
+
}
|
|
194
|
+
// ----- redactions -------------------------------------------------
|
|
195
|
+
/** Burn in redaction annotations on a single page (zero-based). */
|
|
196
|
+
applyPageRedactions(pageIndex) {
|
|
197
|
+
this._throwIfClosed();
|
|
198
|
+
native.editorApplyPageRedactions(this._handle, pageIndex);
|
|
199
|
+
}
|
|
200
|
+
/** Burn in all pending redaction annotations across the document. */
|
|
201
|
+
applyAllRedactions() {
|
|
202
|
+
this._throwIfClosed();
|
|
203
|
+
native.editorApplyAllRedactions(this._handle);
|
|
204
|
+
}
|
|
205
|
+
// ----- rotation (additive) ----------------------------------------
|
|
206
|
+
/** Rotate all pages by `degrees` (additive). */
|
|
207
|
+
rotateAllPages(degrees) {
|
|
208
|
+
this._throwIfClosed();
|
|
209
|
+
native.editorRotateAllPages(this._handle, degrees);
|
|
210
|
+
}
|
|
211
|
+
/** Rotate a single page by `degrees` (additive). */
|
|
212
|
+
rotatePageBy(pageIndex, degrees) {
|
|
213
|
+
this._throwIfClosed();
|
|
214
|
+
native.editorRotatePageBy(this._handle, pageIndex, degrees);
|
|
215
|
+
}
|
|
216
|
+
// ----- page boxes -------------------------------------------------
|
|
217
|
+
/** Get the MediaBox of a page as `{x, y, width, height}`. */
|
|
218
|
+
getPageMediaBox(pageIndex) {
|
|
219
|
+
this._throwIfClosed();
|
|
220
|
+
return native.editorGetPageMediaBox(this._handle, pageIndex);
|
|
221
|
+
}
|
|
222
|
+
/** Set the MediaBox of a page. */
|
|
223
|
+
setPageMediaBox(pageIndex, x, y, width, height) {
|
|
224
|
+
this._throwIfClosed();
|
|
225
|
+
native.editorSetPageMediaBox(this._handle, pageIndex, x, y, width, height);
|
|
226
|
+
}
|
|
227
|
+
/** Get the CropBox of a page. Returns `{x:0,y:0,width:0,height:0}` if none set. */
|
|
228
|
+
getPageCropBox(pageIndex) {
|
|
229
|
+
this._throwIfClosed();
|
|
230
|
+
return native.editorGetPageCropBox(this._handle, pageIndex);
|
|
231
|
+
}
|
|
232
|
+
/** Set the CropBox of a page. */
|
|
233
|
+
setPageCropBox(pageIndex, x, y, width, height) {
|
|
234
|
+
this._throwIfClosed();
|
|
235
|
+
native.editorSetPageCropBox(this._handle, pageIndex, x, y, width, height);
|
|
236
|
+
}
|
|
237
|
+
// ----- erase regions ----------------------------------------------
|
|
238
|
+
/**
|
|
239
|
+
* Erase rectangular regions on a page.
|
|
240
|
+
* `rects` is an array of `[x, y, w, h]` tuples.
|
|
241
|
+
*/
|
|
242
|
+
eraseRegions(pageIndex, rects) {
|
|
243
|
+
this._throwIfClosed();
|
|
244
|
+
native.editorEraseRegions(this._handle, pageIndex, rects);
|
|
245
|
+
}
|
|
246
|
+
/** Clear all pending erase-region entries for a page. */
|
|
247
|
+
clearEraseRegions(pageIndex) {
|
|
248
|
+
this._throwIfClosed();
|
|
249
|
+
native.editorClearEraseRegions(this._handle, pageIndex);
|
|
250
|
+
}
|
|
251
|
+
// ----- form flattening on single page ------------------------------
|
|
252
|
+
/** Flatten form fields on a single page. */
|
|
253
|
+
flattenFormsOnPage(pageIndex) {
|
|
254
|
+
this._throwIfClosed();
|
|
255
|
+
native.editorFlattenFormsOnPage(this._handle, pageIndex);
|
|
256
|
+
}
|
|
257
|
+
// ----- page-mark state queries ------------------------------------
|
|
258
|
+
/** True if the page is marked for annotation-flatten. */
|
|
259
|
+
isPageMarkedForFlatten(pageIndex) {
|
|
260
|
+
this._throwIfClosed();
|
|
261
|
+
return native.editorIsPageMarkedForFlatten(this._handle, pageIndex);
|
|
262
|
+
}
|
|
263
|
+
/** Remove the flatten mark from a page. */
|
|
264
|
+
unmarkPageForFlatten(pageIndex) {
|
|
265
|
+
this._throwIfClosed();
|
|
266
|
+
native.editorUnmarkPageForFlatten(this._handle, pageIndex);
|
|
267
|
+
}
|
|
268
|
+
/** True if the page is marked for redaction. */
|
|
269
|
+
isPageMarkedForRedaction(pageIndex) {
|
|
270
|
+
this._throwIfClosed();
|
|
271
|
+
return native.editorIsPageMarkedForRedaction(this._handle, pageIndex);
|
|
272
|
+
}
|
|
273
|
+
/** Remove the redaction mark from a page. */
|
|
274
|
+
unmarkPageForRedaction(pageIndex) {
|
|
275
|
+
this._throwIfClosed();
|
|
276
|
+
native.editorUnmarkPageForRedaction(this._handle, pageIndex);
|
|
277
|
+
}
|
|
278
|
+
// ----- save paths -------------------------------------------------
|
|
279
|
+
/** Save the document to `path`. */
|
|
280
|
+
save(path) {
|
|
281
|
+
this._throwIfClosed();
|
|
282
|
+
if (typeof path !== 'string' || path.length === 0) {
|
|
283
|
+
throw new TypeError('path must be a non-empty string');
|
|
284
|
+
}
|
|
285
|
+
native.editorSave(this._handle, path);
|
|
286
|
+
}
|
|
287
|
+
/** Save with AES-256 encryption (user + owner passwords). */
|
|
288
|
+
saveEncrypted(path, userPassword, ownerPassword) {
|
|
289
|
+
this._throwIfClosed();
|
|
290
|
+
native.editorSaveEncrypted(this._handle, path, userPassword, ownerPassword);
|
|
291
|
+
}
|
|
292
|
+
/** Extract specific pages (by 0-based index) into a new PDF returned as a Buffer. */
|
|
293
|
+
extractPagesToBytes(pageIndices) {
|
|
294
|
+
this._throwIfClosed();
|
|
295
|
+
return native.editorExtractPagesToBytes(this._handle, pageIndices);
|
|
296
|
+
}
|
|
297
|
+
/** Save the document to an in-memory Buffer. */
|
|
298
|
+
saveToBytes() {
|
|
299
|
+
this._throwIfClosed();
|
|
300
|
+
return native.editorSaveToBytes(this._handle);
|
|
301
|
+
}
|
|
302
|
+
/** Save to an in-memory Buffer with explicit compression / GC / linearize flags. */
|
|
303
|
+
saveToBytesWithOptions(compress, garbageCollect, linearize) {
|
|
304
|
+
this._throwIfClosed();
|
|
305
|
+
return native.editorSaveToBytesWithOptions(this._handle, compress, garbageCollect, linearize);
|
|
306
|
+
}
|
|
307
|
+
// ----- lifecycle --------------------------------------------------
|
|
308
|
+
/** Release the native handle. Safe to call multiple times. */
|
|
309
|
+
close() {
|
|
310
|
+
if (!this._closed) {
|
|
311
|
+
if (native.editorFree) {
|
|
312
|
+
native.editorFree(this._handle);
|
|
313
|
+
}
|
|
314
|
+
this._closed = true;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
export default DocumentEditor;
|