pdf-oxide 0.3.24
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 +218 -0
- package/binding.gyp +35 -0
- package/package.json +78 -0
- package/src/builders/annotation-builder.ts +367 -0
- package/src/builders/conversion-options-builder.ts +257 -0
- package/src/builders/index.ts +12 -0
- package/src/builders/metadata-builder.ts +317 -0
- package/src/builders/pdf-builder.ts +386 -0
- package/src/builders/search-options-builder.ts +151 -0
- package/src/document-editor-manager.ts +318 -0
- package/src/errors.ts +1629 -0
- package/src/form-field-manager.ts +666 -0
- package/src/hybrid-ml-manager.ts +283 -0
- package/src/index.ts +453 -0
- package/src/managers/accessibility-manager.ts +338 -0
- package/src/managers/annotation-manager.ts +439 -0
- package/src/managers/barcode-manager.ts +235 -0
- package/src/managers/batch-manager.ts +533 -0
- package/src/managers/cache-manager.ts +486 -0
- package/src/managers/compliance-manager.ts +375 -0
- package/src/managers/content-manager.ts +339 -0
- package/src/managers/document-utility-manager.ts +922 -0
- package/src/managers/dom-pdf-creator.ts +365 -0
- package/src/managers/editing-manager.ts +514 -0
- package/src/managers/enterprise-manager.ts +478 -0
- package/src/managers/extended-managers.ts +437 -0
- package/src/managers/extraction-manager.ts +583 -0
- package/src/managers/final-utilities.ts +429 -0
- package/src/managers/hybrid-ml-advanced.ts +479 -0
- package/src/managers/index.ts +239 -0
- package/src/managers/layer-manager.ts +500 -0
- package/src/managers/metadata-manager.ts +303 -0
- package/src/managers/ocr-manager.ts +756 -0
- package/src/managers/optimization-manager.ts +262 -0
- package/src/managers/outline-manager.ts +196 -0
- package/src/managers/page-manager.ts +289 -0
- package/src/managers/pattern-detection.ts +440 -0
- package/src/managers/rendering-manager.ts +863 -0
- package/src/managers/search-manager.ts +385 -0
- package/src/managers/security-manager.ts +345 -0
- package/src/managers/signature-manager.ts +1664 -0
- package/src/managers/streams.ts +618 -0
- package/src/managers/xfa-manager.ts +500 -0
- package/src/pdf-creator-manager.ts +494 -0
- package/src/properties.ts +522 -0
- package/src/result-accessors-manager.ts +867 -0
- package/src/tests/advanced-features.test.ts +414 -0
- package/src/tests/advanced.test.ts +266 -0
- package/src/tests/extended-managers.test.ts +316 -0
- package/src/tests/final-utilities.test.ts +455 -0
- package/src/tests/foundation.test.ts +315 -0
- package/src/tests/high-demand.test.ts +257 -0
- package/src/tests/specialized.test.ts +97 -0
- package/src/thumbnail-manager.ts +272 -0
- package/src/types/common.ts +142 -0
- package/src/types/document-types.ts +457 -0
- package/src/types/index.ts +6 -0
- package/src/types/manager-types.ts +284 -0
- package/src/types/native-bindings.ts +517 -0
- package/src/workers/index.ts +7 -0
- package/src/workers/pool.ts +274 -0
- package/src/workers/worker.ts +131 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OptimizationManager - PDF Optimization Operations
|
|
3
|
+
*
|
|
4
|
+
* Provides document optimization capabilities including:
|
|
5
|
+
* - Font subsetting
|
|
6
|
+
* - Image downsampling
|
|
7
|
+
* - Object deduplication
|
|
8
|
+
* - Full optimization pipeline
|
|
9
|
+
*
|
|
10
|
+
* @since 1.0.0
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { EventEmitter } from 'events';
|
|
14
|
+
import { mapFfiErrorCode, OptimizationException } from '../errors';
|
|
15
|
+
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Type Definitions
|
|
18
|
+
// =============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Result of an optimization operation.
|
|
22
|
+
*/
|
|
23
|
+
export interface OptimizationResult {
|
|
24
|
+
/** Whether the optimization succeeded */
|
|
25
|
+
readonly success: boolean;
|
|
26
|
+
/** Number of bytes saved */
|
|
27
|
+
readonly bytesSaved: number;
|
|
28
|
+
/** Original document size in bytes */
|
|
29
|
+
readonly originalSize: number;
|
|
30
|
+
/** Optimized document size in bytes */
|
|
31
|
+
readonly optimizedSize: number;
|
|
32
|
+
/** Compression ratio (0.0 - 1.0) */
|
|
33
|
+
readonly compressionRatio: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// OptimizationManager
|
|
38
|
+
// =============================================================================
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Manager for PDF optimization operations.
|
|
42
|
+
*
|
|
43
|
+
* Provides methods for reducing PDF file size through font subsetting,
|
|
44
|
+
* image downsampling, object deduplication, and combined optimization.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const optimizer = new OptimizationManager(document);
|
|
49
|
+
*
|
|
50
|
+
* // Subset fonts to remove unused glyphs
|
|
51
|
+
* const fontResult = await optimizer.subsetFonts();
|
|
52
|
+
* console.log(`Font subsetting saved ${fontResult.bytesSaved} bytes`);
|
|
53
|
+
*
|
|
54
|
+
* // Downsample high-resolution images
|
|
55
|
+
* const imageResult = await optimizer.downsampleImages(150, 80);
|
|
56
|
+
*
|
|
57
|
+
* // Full optimization pipeline
|
|
58
|
+
* const fullResult = await optimizer.optimizeFull(150, 80);
|
|
59
|
+
* console.log(`Total savings: ${fullResult.bytesSaved} bytes`);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export class OptimizationManager extends EventEmitter {
|
|
63
|
+
private document: any;
|
|
64
|
+
private native: any;
|
|
65
|
+
|
|
66
|
+
constructor(document: any) {
|
|
67
|
+
super();
|
|
68
|
+
if (!document) {
|
|
69
|
+
throw new Error('Document cannot be null or undefined');
|
|
70
|
+
}
|
|
71
|
+
this.document = document;
|
|
72
|
+
try {
|
|
73
|
+
this.native = require('../../index.node');
|
|
74
|
+
} catch {
|
|
75
|
+
this.native = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ===========================================================================
|
|
80
|
+
// Optimization Operations
|
|
81
|
+
// ===========================================================================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Subsets all embedded fonts in the document.
|
|
85
|
+
*
|
|
86
|
+
* Removes unused glyphs from embedded fonts, reducing file size
|
|
87
|
+
* while preserving visual fidelity for the characters actually used.
|
|
88
|
+
*
|
|
89
|
+
* @returns Optimization result with bytes saved
|
|
90
|
+
* @throws OptimizationException if the operation fails
|
|
91
|
+
*/
|
|
92
|
+
async subsetFonts(): Promise<OptimizationResult> {
|
|
93
|
+
if (!this.native?.pdf_optimize_subset_fonts) {
|
|
94
|
+
throw new OptimizationException('Native optimization not available: pdf_optimize_subset_fonts not found');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const errorCode = Buffer.alloc(4);
|
|
98
|
+
const resultPtr = this.native.pdf_optimize_subset_fonts(
|
|
99
|
+
this.document._handle ?? this.document,
|
|
100
|
+
errorCode,
|
|
101
|
+
);
|
|
102
|
+
const code = errorCode.readInt32LE(0);
|
|
103
|
+
|
|
104
|
+
if (code !== 0) {
|
|
105
|
+
throw mapFfiErrorCode(code, 'Failed to subset fonts');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = this.parseOptimizationResult(resultPtr);
|
|
109
|
+
this.emit('fonts-subsetted', { bytesSaved: result.bytesSaved });
|
|
110
|
+
|
|
111
|
+
this.freeOptimizationResult(resultPtr);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Downsamples images in the document to reduce file size.
|
|
117
|
+
*
|
|
118
|
+
* @param dpi - Target resolution in dots per inch (default: 150)
|
|
119
|
+
* @param quality - JPEG quality for recompression (1-100, default: 80)
|
|
120
|
+
* @returns Optimization result with bytes saved
|
|
121
|
+
* @throws OptimizationException if the operation fails
|
|
122
|
+
*/
|
|
123
|
+
async downsampleImages(dpi?: number, quality?: number): Promise<OptimizationResult> {
|
|
124
|
+
if (!this.native?.pdf_optimize_downsample_images) {
|
|
125
|
+
throw new OptimizationException('Native optimization not available: pdf_optimize_downsample_images not found');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const errorCode = Buffer.alloc(4);
|
|
129
|
+
const resultPtr = this.native.pdf_optimize_downsample_images(
|
|
130
|
+
this.document._handle ?? this.document,
|
|
131
|
+
dpi ?? 150,
|
|
132
|
+
quality ?? 80,
|
|
133
|
+
errorCode,
|
|
134
|
+
);
|
|
135
|
+
const code = errorCode.readInt32LE(0);
|
|
136
|
+
|
|
137
|
+
if (code !== 0) {
|
|
138
|
+
throw mapFfiErrorCode(code, 'Failed to downsample images');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const result = this.parseOptimizationResult(resultPtr);
|
|
142
|
+
this.emit('images-downsampled', { dpi: dpi ?? 150, quality: quality ?? 80, bytesSaved: result.bytesSaved });
|
|
143
|
+
|
|
144
|
+
this.freeOptimizationResult(resultPtr);
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Deduplicates identical objects in the document.
|
|
150
|
+
*
|
|
151
|
+
* Identifies and merges duplicate fonts, images, and other resources
|
|
152
|
+
* that appear multiple times in the document.
|
|
153
|
+
*
|
|
154
|
+
* @returns Optimization result with bytes saved
|
|
155
|
+
* @throws OptimizationException if the operation fails
|
|
156
|
+
*/
|
|
157
|
+
async deduplicate(): Promise<OptimizationResult> {
|
|
158
|
+
if (!this.native?.pdf_optimize_deduplicate) {
|
|
159
|
+
throw new OptimizationException('Native optimization not available: pdf_optimize_deduplicate not found');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const errorCode = Buffer.alloc(4);
|
|
163
|
+
const resultPtr = this.native.pdf_optimize_deduplicate(
|
|
164
|
+
this.document._handle ?? this.document,
|
|
165
|
+
errorCode,
|
|
166
|
+
);
|
|
167
|
+
const code = errorCode.readInt32LE(0);
|
|
168
|
+
|
|
169
|
+
if (code !== 0) {
|
|
170
|
+
throw mapFfiErrorCode(code, 'Failed to deduplicate objects');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const result = this.parseOptimizationResult(resultPtr);
|
|
174
|
+
this.emit('deduplicated', { bytesSaved: result.bytesSaved });
|
|
175
|
+
|
|
176
|
+
this.freeOptimizationResult(resultPtr);
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Runs the full optimization pipeline.
|
|
182
|
+
*
|
|
183
|
+
* Combines font subsetting, image downsampling, and object deduplication
|
|
184
|
+
* into a single operation for maximum file size reduction.
|
|
185
|
+
*
|
|
186
|
+
* @param dpi - Target image resolution in dots per inch (default: 150)
|
|
187
|
+
* @param quality - JPEG quality for recompression (1-100, default: 80)
|
|
188
|
+
* @returns Optimization result with total bytes saved
|
|
189
|
+
* @throws OptimizationException if the operation fails
|
|
190
|
+
*/
|
|
191
|
+
async optimizeFull(dpi?: number, quality?: number): Promise<OptimizationResult> {
|
|
192
|
+
if (!this.native?.pdf_optimize_full) {
|
|
193
|
+
throw new OptimizationException('Native optimization not available: pdf_optimize_full not found');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const errorCode = Buffer.alloc(4);
|
|
197
|
+
const resultPtr = this.native.pdf_optimize_full(
|
|
198
|
+
this.document._handle ?? this.document,
|
|
199
|
+
dpi ?? 150,
|
|
200
|
+
quality ?? 80,
|
|
201
|
+
errorCode,
|
|
202
|
+
);
|
|
203
|
+
const code = errorCode.readInt32LE(0);
|
|
204
|
+
|
|
205
|
+
if (code !== 0) {
|
|
206
|
+
throw mapFfiErrorCode(code, 'Failed to run full optimization');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const result = this.parseOptimizationResult(resultPtr);
|
|
210
|
+
this.emit('optimized-full', { dpi: dpi ?? 150, quality: quality ?? 80, bytesSaved: result.bytesSaved });
|
|
211
|
+
|
|
212
|
+
this.freeOptimizationResult(resultPtr);
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ===========================================================================
|
|
217
|
+
// Private Helpers
|
|
218
|
+
// ===========================================================================
|
|
219
|
+
|
|
220
|
+
private parseOptimizationResult(resultPtr: any): OptimizationResult {
|
|
221
|
+
if (!resultPtr) {
|
|
222
|
+
return { success: true, bytesSaved: 0, originalSize: 0, optimizedSize: 0, compressionRatio: 0 };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (typeof resultPtr === 'string') {
|
|
226
|
+
try {
|
|
227
|
+
return JSON.parse(resultPtr);
|
|
228
|
+
} catch {
|
|
229
|
+
return { success: true, bytesSaved: 0, originalSize: 0, optimizedSize: 0, compressionRatio: 0 };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Handle native result handle
|
|
234
|
+
const bytesSaved = this.native?.pdf_optimization_result_bytes_saved?.(resultPtr) ?? 0;
|
|
235
|
+
return {
|
|
236
|
+
success: true,
|
|
237
|
+
bytesSaved,
|
|
238
|
+
originalSize: 0,
|
|
239
|
+
optimizedSize: 0,
|
|
240
|
+
compressionRatio: 0,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private freeOptimizationResult(resultPtr: any): void {
|
|
245
|
+
if (resultPtr && typeof resultPtr !== 'string' && this.native?.pdf_optimization_result_free) {
|
|
246
|
+
this.native.pdf_optimization_result_free(resultPtr);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ===========================================================================
|
|
251
|
+
// Cleanup
|
|
252
|
+
// ===========================================================================
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Releases resources held by this manager.
|
|
256
|
+
*/
|
|
257
|
+
destroy(): void {
|
|
258
|
+
this.removeAllListeners();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export default OptimizationManager;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manager for PDF document outlines (bookmarks)
|
|
3
|
+
*
|
|
4
|
+
* Provides functionality for reading and navigating the document's outline tree,
|
|
5
|
+
* which represents the hierarchical bookmark structure.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { OutlineManager } from 'pdf_oxide';
|
|
10
|
+
*
|
|
11
|
+
* const doc = PdfDocument.open('document.pdf');
|
|
12
|
+
* const outlineManager = new OutlineManager(doc);
|
|
13
|
+
*
|
|
14
|
+
* if (outlineManager.hasOutlines()) {
|
|
15
|
+
* const outlines = outlineManager.getOutlines();
|
|
16
|
+
* console.log(`Found ${outlines.length} outline items`);
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export interface OutlineItem {
|
|
22
|
+
title: string;
|
|
23
|
+
pageIndex: number;
|
|
24
|
+
pageNumber: number | null;
|
|
25
|
+
level: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class OutlineManager {
|
|
29
|
+
private _document: any;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a new OutlineManager for the given document
|
|
33
|
+
* @param document - The PDF document
|
|
34
|
+
* @throws Error if document is null or undefined
|
|
35
|
+
*/
|
|
36
|
+
constructor(document: any) {
|
|
37
|
+
if (!document) {
|
|
38
|
+
throw new Error('Document is required');
|
|
39
|
+
}
|
|
40
|
+
this._document = document;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Checks if the document has an outline (bookmarks)
|
|
45
|
+
* @returns True if the document has outlines
|
|
46
|
+
*/
|
|
47
|
+
hasOutlines(): boolean {
|
|
48
|
+
try {
|
|
49
|
+
return this._document.hasOutlines();
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Gets the number of top-level outline items
|
|
57
|
+
* @returns Number of outline items
|
|
58
|
+
*/
|
|
59
|
+
getOutlineCount(): number {
|
|
60
|
+
try {
|
|
61
|
+
return this._document.getOutlineCount();
|
|
62
|
+
} catch (error) {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Gets all outline items (flattened)
|
|
69
|
+
* @returns Array of outline items
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const outlines = manager.getOutlines();
|
|
74
|
+
* outlines.forEach(item => {
|
|
75
|
+
* console.log(`${item.title} -> Page ${item.pageNumber}`);
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
getOutlines(): OutlineItem[] {
|
|
80
|
+
try {
|
|
81
|
+
const rawOutlines = this._document.getOutlines();
|
|
82
|
+
// Convert native OutlineInfo to OutlineItem format expected by JS
|
|
83
|
+
return rawOutlines.map((item: any) => ({
|
|
84
|
+
title: item.title,
|
|
85
|
+
pageIndex: item.pageIndex,
|
|
86
|
+
pageNumber: item.pageIndex >= 0 ? item.pageIndex + 1 : null,
|
|
87
|
+
level: item.level,
|
|
88
|
+
}));
|
|
89
|
+
} catch (error) {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Finds an outline item by title (case-insensitive substring match)
|
|
96
|
+
* @param titleFragment - Partial title to search for
|
|
97
|
+
* @returns Matching outline item or null
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const item = manager.findByTitle('Introduction');
|
|
102
|
+
* if (item) {
|
|
103
|
+
* console.log(`Found: ${item.title} on page ${item.pageNumber}`);
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
findByTitle(titleFragment: string): OutlineItem | null {
|
|
108
|
+
if (!titleFragment || typeof titleFragment !== 'string') {
|
|
109
|
+
throw new Error('Title fragment must be a non-empty string');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const outlines = this.getOutlines();
|
|
113
|
+
const fragment = titleFragment.toLowerCase();
|
|
114
|
+
|
|
115
|
+
for (const item of outlines) {
|
|
116
|
+
if (item.title && item.title.toLowerCase().includes(fragment)) {
|
|
117
|
+
return item;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Finds all outline items by title (case-insensitive substring match)
|
|
126
|
+
* @param titleFragment - Partial title to search for
|
|
127
|
+
* @returns Array of matching outline items
|
|
128
|
+
*/
|
|
129
|
+
findAllByTitle(titleFragment: string): OutlineItem[] {
|
|
130
|
+
if (!titleFragment || typeof titleFragment !== 'string') {
|
|
131
|
+
throw new Error('Title fragment must be a non-empty string');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const outlines = this.getOutlines();
|
|
135
|
+
const fragment = titleFragment.toLowerCase();
|
|
136
|
+
|
|
137
|
+
return outlines.filter((item) =>
|
|
138
|
+
item.title && item.title.toLowerCase().includes(fragment)
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Gets outline items for a specific page
|
|
144
|
+
* @param pageIndex - Zero-based page index
|
|
145
|
+
* @returns Outline items on that page
|
|
146
|
+
*/
|
|
147
|
+
getOutlinesForPage(pageIndex: number): OutlineItem[] {
|
|
148
|
+
if (typeof pageIndex !== 'number' || pageIndex < 0) {
|
|
149
|
+
throw new Error('Page index must be a non-negative number');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const outlines = this.getOutlines();
|
|
153
|
+
return outlines.filter((item) => item.pageIndex === pageIndex);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Checks if a specific page has outline items
|
|
158
|
+
* @param pageIndex - Zero-based page index
|
|
159
|
+
* @returns True if page has outline items
|
|
160
|
+
*/
|
|
161
|
+
pageHasOutlines(pageIndex: number): boolean {
|
|
162
|
+
if (typeof pageIndex !== 'number' || pageIndex < 0) {
|
|
163
|
+
throw new Error('Page index must be a non-negative number');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return this.getOutlinesForPage(pageIndex).length > 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Gets an outline item by index
|
|
171
|
+
* @param index - Item index
|
|
172
|
+
* @returns Outline item or null if not found
|
|
173
|
+
*/
|
|
174
|
+
getOutlineAt(index: number): OutlineItem | null {
|
|
175
|
+
if (typeof index !== 'number' || index < 0) {
|
|
176
|
+
throw new Error('Index must be a non-negative number');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const outlines = this.getOutlines();
|
|
180
|
+
return outlines[index] || null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Checks if a page number exists in the outline
|
|
185
|
+
* @param pageNumber - One-based page number
|
|
186
|
+
* @returns True if page appears in outline
|
|
187
|
+
*/
|
|
188
|
+
containsPageNumber(pageNumber: number): boolean {
|
|
189
|
+
if (typeof pageNumber !== 'number' || pageNumber < 1) {
|
|
190
|
+
throw new Error('Page number must be a positive number');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const outlines = this.getOutlines();
|
|
194
|
+
return outlines.some((item) => item.pageNumber === pageNumber);
|
|
195
|
+
}
|
|
196
|
+
}
|