react-native-pdf-jsi 2.2.8 → 3.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 +308 -173
- package/android/src/main/java/org/wonday/pdf/FileDownloader.java +292 -0
- package/android/src/main/java/org/wonday/pdf/FileManager.java +123 -0
- package/android/src/main/java/org/wonday/pdf/LicenseVerifier.java +311 -0
- package/android/src/main/java/org/wonday/pdf/PDFExporter.java +769 -0
- package/android/src/main/java/org/wonday/pdf/RNPDFPackage.java +7 -0
- package/index.js +58 -0
- package/ios/RNPDFPdf/PDFExporter.h +16 -0
- package/ios/RNPDFPdf/PDFExporter.m +537 -0
- package/package.json +3 -2
- package/src/components/AnalyticsPanel.jsx +243 -0
- package/src/components/BookmarkIndicator.jsx +66 -0
- package/src/components/BookmarkListModal.jsx +378 -0
- package/src/components/BookmarkModal.jsx +253 -0
- package/src/components/BottomSheet.jsx +121 -0
- package/src/components/ExportMenu.jsx +223 -0
- package/src/components/LoadingOverlay.jsx +52 -0
- package/src/components/OperationsMenu.jsx +231 -0
- package/src/components/SidePanel.jsx +95 -0
- package/src/components/Toast.jsx +140 -0
- package/src/components/Toolbar.jsx +135 -0
- package/src/managers/AnalyticsManager.js +695 -0
- package/src/managers/BookmarkManager.js +538 -0
- package/src/managers/ExportManager.js +687 -0
- package/src/managers/FileManager.js +89 -0
- package/src/utils/ErrorHandler.js +179 -0
- package/src/utils/TestData.js +112 -0
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExportManager - PDF Export and Conversion Manager
|
|
3
|
+
* Handles exporting PDFs to various formats and PDF operations
|
|
4
|
+
*
|
|
5
|
+
* LICENSE:
|
|
6
|
+
* - Export to text: MIT License (Free)
|
|
7
|
+
* - Export to images: Commercial License (Paid)
|
|
8
|
+
* - PDF operations: Commercial License (Paid)
|
|
9
|
+
*
|
|
10
|
+
* @author Punith M
|
|
11
|
+
* @version 1.0.0
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { NativeModules, Platform, Share } from 'react-native';
|
|
15
|
+
import PDFTextExtractor from '../utils/PDFTextExtractor';
|
|
16
|
+
import licenseManager, { ProFeature } from '../license/LicenseManager';
|
|
17
|
+
|
|
18
|
+
const { PDFExporter } = NativeModules;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Export formats supported
|
|
22
|
+
*/
|
|
23
|
+
export const ExportFormat = {
|
|
24
|
+
TEXT: 'text',
|
|
25
|
+
JPEG: 'jpeg',
|
|
26
|
+
PNG: 'png',
|
|
27
|
+
PDF: 'pdf'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Export quality levels
|
|
32
|
+
*/
|
|
33
|
+
export const ExportQuality = {
|
|
34
|
+
LOW: 0.5,
|
|
35
|
+
MEDIUM: 0.75,
|
|
36
|
+
HIGH: 0.9,
|
|
37
|
+
BEST: 1.0
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* ExportManager Class
|
|
42
|
+
*/
|
|
43
|
+
export class ExportManager {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.isNativeAvailable = !!PDFExporter;
|
|
46
|
+
|
|
47
|
+
if (!this.isNativeAvailable) {
|
|
48
|
+
console.warn('📤 ExportManager: Native module not available - using fallback methods');
|
|
49
|
+
} else {
|
|
50
|
+
console.log('📤 ExportManager: Initialized (version ' + PDFExporter.VERSION + ')');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check if export functionality is available
|
|
56
|
+
* @returns {boolean} True if available
|
|
57
|
+
*/
|
|
58
|
+
isAvailable() {
|
|
59
|
+
return this.isNativeAvailable || PDFTextExtractor.isTextExtractionAvailable();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Convert quality string to numeric value
|
|
64
|
+
* @private
|
|
65
|
+
* @param {string|number} quality - Quality as string ('low', 'medium', 'high', 'best') or number (0.5-1.0)
|
|
66
|
+
* @returns {number} Normalized quality as number
|
|
67
|
+
*/
|
|
68
|
+
_normalizeQuality(quality) {
|
|
69
|
+
// If already numeric, return as-is
|
|
70
|
+
if (typeof quality === 'number') {
|
|
71
|
+
return quality;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Convert string to numeric
|
|
75
|
+
const qualityMap = {
|
|
76
|
+
'low': ExportQuality.LOW, // 0.5
|
|
77
|
+
'medium': ExportQuality.MEDIUM, // 0.75
|
|
78
|
+
'high': ExportQuality.HIGH, // 0.9
|
|
79
|
+
'best': ExportQuality.BEST // 1.0
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const normalized = qualityMap[quality?.toLowerCase()];
|
|
83
|
+
return normalized !== undefined ? normalized : ExportQuality.HIGH; // default to HIGH
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ============================================
|
|
87
|
+
// EXPORT TO TEXT
|
|
88
|
+
// ============================================
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Export PDF to plain text
|
|
92
|
+
* @param {string} filePath - Path to PDF file
|
|
93
|
+
* @param {Object} options - Export options
|
|
94
|
+
* @returns {Promise<string>} Exported text content
|
|
95
|
+
*/
|
|
96
|
+
async exportToText(filePath, options = {}) {
|
|
97
|
+
const {
|
|
98
|
+
pages = null, // null = all pages, or array of page numbers
|
|
99
|
+
includePageNumbers = true,
|
|
100
|
+
separator = '\n\n--- Page {page} ---\n\n',
|
|
101
|
+
encoding = 'utf8'
|
|
102
|
+
} = options;
|
|
103
|
+
|
|
104
|
+
console.log('📤 ExportManager: Exporting to text...');
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
// Use text extractor
|
|
108
|
+
let textMap;
|
|
109
|
+
|
|
110
|
+
if (pages) {
|
|
111
|
+
// Convert to 0-indexed
|
|
112
|
+
const pageIndices = pages.map(p => p - 1);
|
|
113
|
+
textMap = await PDFTextExtractor.extractTextFromPages(filePath, pageIndices);
|
|
114
|
+
} else {
|
|
115
|
+
textMap = await PDFTextExtractor.extractAllText(filePath);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Build text document
|
|
119
|
+
let result = '';
|
|
120
|
+
const sortedPages = Array.from(textMap.keys()).sort((a, b) => a - b);
|
|
121
|
+
|
|
122
|
+
sortedPages.forEach((pageNum, index) => {
|
|
123
|
+
const text = textMap.get(pageNum);
|
|
124
|
+
|
|
125
|
+
if (includePageNumbers && index > 0) {
|
|
126
|
+
const sep = separator.replace('{page}', pageNum + 1);
|
|
127
|
+
result += sep;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
result += text;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
console.log(`📤 ExportManager: Exported ${result.length} characters from ${sortedPages.length} pages`);
|
|
134
|
+
return result;
|
|
135
|
+
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error('📤 ExportManager: Export to text error:', error);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Export page to text (single page)
|
|
144
|
+
* @param {string} filePath - Path to PDF file
|
|
145
|
+
* @param {number} pageNumber - Page number (1-indexed)
|
|
146
|
+
* @returns {Promise<string>} Page text
|
|
147
|
+
*/
|
|
148
|
+
async exportPageToText(filePath, pageNumber) {
|
|
149
|
+
try {
|
|
150
|
+
const text = await PDFTextExtractor.extractTextFromPage(filePath, pageNumber - 1);
|
|
151
|
+
console.log(`📤 ExportManager: Exported page ${pageNumber} (${text.length} chars)`);
|
|
152
|
+
return text;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error('📤 ExportManager: Export page error:', error);
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ============================================
|
|
160
|
+
// EXPORT TO IMAGES
|
|
161
|
+
// ============================================
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Export PDF pages to images
|
|
165
|
+
* @param {string} filePath - Path to PDF file
|
|
166
|
+
* @param {Object} options - Export options
|
|
167
|
+
* @returns {Promise<Array>} Array of image paths
|
|
168
|
+
*/
|
|
169
|
+
async exportToImages(filePath, options = {}) {
|
|
170
|
+
// ⚠️ PRO FEATURE - Requires license
|
|
171
|
+
licenseManager.requirePro('Export to Images');
|
|
172
|
+
|
|
173
|
+
const {
|
|
174
|
+
pages = null, // null = all pages
|
|
175
|
+
format = ExportFormat.JPEG,
|
|
176
|
+
quality = ExportQuality.HIGH,
|
|
177
|
+
width = null, // null = original width
|
|
178
|
+
height = null, // null = original height
|
|
179
|
+
scale = 2.0 // Scale factor for rendering
|
|
180
|
+
} = options;
|
|
181
|
+
|
|
182
|
+
console.log('📤 ExportManager: Exporting to images...');
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
if (this.isNativeAvailable) {
|
|
186
|
+
// Use native exporter
|
|
187
|
+
const images = await PDFExporter.exportToImages(filePath, {
|
|
188
|
+
pages: pages || [],
|
|
189
|
+
format,
|
|
190
|
+
quality,
|
|
191
|
+
width,
|
|
192
|
+
height,
|
|
193
|
+
scale
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
console.log(`📤 ExportManager: Exported ${images.length} images`);
|
|
197
|
+
return images;
|
|
198
|
+
} else {
|
|
199
|
+
// Fallback: Use screenshot-based approach
|
|
200
|
+
console.warn('📤 ExportManager: Native export not available, using fallback');
|
|
201
|
+
return this.exportToImagesFallback(filePath, options);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('📤 ExportManager: Export to images error:', error);
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Export single page to image
|
|
212
|
+
* @param {string} filePath - Path to PDF file
|
|
213
|
+
* @param {number} pageNumber - Page number (1-indexed)
|
|
214
|
+
* @param {Object} options - Export options
|
|
215
|
+
* @returns {Promise<string>} Image file path
|
|
216
|
+
*/
|
|
217
|
+
async exportPageToImage(filePath, pageNumber, options = {}) {
|
|
218
|
+
const {
|
|
219
|
+
format = ExportFormat.JPEG,
|
|
220
|
+
quality = ExportQuality.HIGH,
|
|
221
|
+
scale = 2.0
|
|
222
|
+
} = options;
|
|
223
|
+
|
|
224
|
+
console.log(`🖼️ [ExportManager] exportPageToImage - START`, {
|
|
225
|
+
filePath,
|
|
226
|
+
pageNumber,
|
|
227
|
+
format,
|
|
228
|
+
quality,
|
|
229
|
+
scale
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
// ⚠️ PRO FEATURE - Requires license
|
|
234
|
+
console.log('🔑 [ExportManager] Checking license for Export to Images...');
|
|
235
|
+
licenseManager.requirePro('Export to Images');
|
|
236
|
+
console.log('✅ [ExportManager] License check passed');
|
|
237
|
+
|
|
238
|
+
if (this.isNativeAvailable) {
|
|
239
|
+
console.log('📱 [ExportManager] Calling native PDFExporter.exportPageToImage...');
|
|
240
|
+
console.log('📱 [ExportManager] Parameters:', {
|
|
241
|
+
pageIndex: pageNumber - 1,
|
|
242
|
+
format,
|
|
243
|
+
quality,
|
|
244
|
+
scale
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const imagePath = await PDFExporter.exportPageToImage(filePath, pageNumber - 1, {
|
|
248
|
+
format,
|
|
249
|
+
quality: this._normalizeQuality(quality),
|
|
250
|
+
scale
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
console.log('✅ [ExportManager] exportPageToImage - SUCCESS', {
|
|
254
|
+
outputPath: imagePath
|
|
255
|
+
});
|
|
256
|
+
return imagePath;
|
|
257
|
+
} else {
|
|
258
|
+
console.error('❌ [ExportManager] Native export module not available');
|
|
259
|
+
throw new Error('Native export module not available');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error('❌ [ExportManager] exportPageToImage - ERROR:', error.message);
|
|
264
|
+
console.error('❌ [ExportManager] Error details:', error);
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ============================================
|
|
270
|
+
// PDF OPERATIONS
|
|
271
|
+
// ============================================
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Merge multiple PDFs into one
|
|
275
|
+
* @param {string[]} filePaths - Array of PDF file paths
|
|
276
|
+
* @param {string} outputPath - Output file path
|
|
277
|
+
* @returns {Promise<string>} Path to merged PDF
|
|
278
|
+
*/
|
|
279
|
+
async mergePDFs(filePaths, outputPath = null) {
|
|
280
|
+
// ⚠️ PRO FEATURE - Requires license
|
|
281
|
+
licenseManager.requirePro('PDF Operations');
|
|
282
|
+
|
|
283
|
+
console.log(`📤 ExportManager: Merging ${filePaths.length} PDFs...`);
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
if (this.isNativeAvailable) {
|
|
287
|
+
const mergedPath = await PDFExporter.mergePDFs(filePaths, outputPath);
|
|
288
|
+
console.log('📤 ExportManager: Merged to:', mergedPath);
|
|
289
|
+
return mergedPath;
|
|
290
|
+
} else {
|
|
291
|
+
throw new Error('PDF merge requires native module');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error('📤 ExportManager: Merge PDFs error:', error);
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Split PDF into multiple files
|
|
302
|
+
* @param {string} filePath - Path to PDF file
|
|
303
|
+
* @param {Array} ranges - Flat array of page range pairs [start1, end1, start2, end2, ...]
|
|
304
|
+
* @param {string} outputDir - Output directory
|
|
305
|
+
* @returns {Promise<Array>} Array of split PDF paths
|
|
306
|
+
*/
|
|
307
|
+
async splitPDF(filePath, ranges, outputDir = null) {
|
|
308
|
+
console.log(`✂️ [ExportManager] splitPDF - START`, {
|
|
309
|
+
filePath,
|
|
310
|
+
ranges,
|
|
311
|
+
outputDir,
|
|
312
|
+
rangeCount: ranges.length
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
console.log('🔑 [ExportManager] Checking license for PDF Operations...');
|
|
317
|
+
licenseManager.requirePro('PDF Operations');
|
|
318
|
+
console.log('✅ [ExportManager] License check passed');
|
|
319
|
+
|
|
320
|
+
if (this.isNativeAvailable) {
|
|
321
|
+
console.log('📱 [ExportManager] Calling native PDFExporter.splitPDF...');
|
|
322
|
+
console.log('📱 [ExportManager] Ranges:', JSON.stringify(ranges));
|
|
323
|
+
|
|
324
|
+
const splitPaths = await PDFExporter.splitPDF(filePath, ranges, outputDir);
|
|
325
|
+
|
|
326
|
+
console.log(`✅ [ExportManager] splitPDF - SUCCESS - Split into ${splitPaths.length} files`);
|
|
327
|
+
console.log('📁 [ExportManager] Split files:', splitPaths);
|
|
328
|
+
return splitPaths;
|
|
329
|
+
} else {
|
|
330
|
+
console.error('❌ [ExportManager] PDF split requires native module');
|
|
331
|
+
throw new Error('PDF split requires native module');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
} catch (error) {
|
|
335
|
+
console.error('❌ [ExportManager] splitPDF - ERROR:', error.message);
|
|
336
|
+
console.error('❌ [ExportManager] Error details:', error);
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Extract pages from PDF
|
|
343
|
+
* @param {string} filePath - Path to PDF file
|
|
344
|
+
* @param {number[]} pages - Page numbers to extract (1-indexed)
|
|
345
|
+
* @param {string} outputPath - Output file path
|
|
346
|
+
* @returns {Promise<string>} Path to new PDF with extracted pages
|
|
347
|
+
*/
|
|
348
|
+
async extractPages(filePath, pages, outputPath = null) {
|
|
349
|
+
console.log(`✂️ [ExportManager] extractPages - START`, {
|
|
350
|
+
filePath,
|
|
351
|
+
pages,
|
|
352
|
+
pageCount: pages.length,
|
|
353
|
+
outputPath
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
console.log('🔑 [ExportManager] Checking license for PDF Operations...');
|
|
358
|
+
licenseManager.requirePro('PDF Operations');
|
|
359
|
+
console.log('✅ [ExportManager] License check passed');
|
|
360
|
+
|
|
361
|
+
if (this.isNativeAvailable) {
|
|
362
|
+
// Convert to 0-indexed
|
|
363
|
+
const pageIndices = pages.map(p => p - 1);
|
|
364
|
+
|
|
365
|
+
console.log('📱 [ExportManager] Calling native PDFExporter.extractPages...');
|
|
366
|
+
console.log('📱 [ExportManager] Parameters:', {
|
|
367
|
+
pageIndices,
|
|
368
|
+
outputPath: outputPath || 'auto-generated'
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
const extractedPath = await PDFExporter.extractPages(filePath, pageIndices, outputPath);
|
|
372
|
+
|
|
373
|
+
console.log('✅ [ExportManager] extractPages - SUCCESS', {
|
|
374
|
+
extractedPath
|
|
375
|
+
});
|
|
376
|
+
return extractedPath;
|
|
377
|
+
} else {
|
|
378
|
+
console.error('❌ [ExportManager] PDF page extraction requires native module');
|
|
379
|
+
throw new Error('PDF page extraction requires native module');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
} catch (error) {
|
|
383
|
+
console.error('❌ [ExportManager] extractPages - ERROR:', error.message);
|
|
384
|
+
console.error('❌ [ExportManager] Error details:', error);
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Rotate pages in PDF
|
|
391
|
+
* @param {string} filePath - Path to PDF file
|
|
392
|
+
* @param {Object} rotations - Map of page number to rotation degrees
|
|
393
|
+
* @param {string} outputPath - Output file path
|
|
394
|
+
* @returns {Promise<string>} Path to rotated PDF
|
|
395
|
+
*/
|
|
396
|
+
async rotatePages(filePath, rotations, outputPath = null) {
|
|
397
|
+
console.log('📤 ExportManager: Rotating pages...');
|
|
398
|
+
|
|
399
|
+
try {
|
|
400
|
+
if (this.isNativeAvailable) {
|
|
401
|
+
const rotatedPath = await PDFExporter.rotatePages(filePath, rotations, outputPath);
|
|
402
|
+
console.log('📤 ExportManager: Rotated PDF saved to:', rotatedPath);
|
|
403
|
+
return rotatedPath;
|
|
404
|
+
} else {
|
|
405
|
+
throw new Error('PDF rotation requires native module');
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error('📤 ExportManager: Rotate pages error:', error);
|
|
410
|
+
throw error;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Delete pages from PDF
|
|
416
|
+
* @param {string} filePath - Path to PDF file
|
|
417
|
+
* @param {number[]} pages - Page numbers to delete (1-indexed)
|
|
418
|
+
* @param {string} outputPath - Output file path
|
|
419
|
+
* @returns {Promise<string>} Path to new PDF
|
|
420
|
+
*/
|
|
421
|
+
async deletePages(filePath, pages, outputPath = null) {
|
|
422
|
+
console.log(`📤 ExportManager: Deleting ${pages.length} pages...`);
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
if (this.isNativeAvailable) {
|
|
426
|
+
// Convert to 0-indexed
|
|
427
|
+
const pageIndices = pages.map(p => p - 1);
|
|
428
|
+
const newPath = await PDFExporter.deletePages(filePath, pageIndices, outputPath);
|
|
429
|
+
console.log('📤 ExportManager: New PDF saved to:', newPath);
|
|
430
|
+
return newPath;
|
|
431
|
+
} else {
|
|
432
|
+
throw new Error('PDF page deletion requires native module');
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
} catch (error) {
|
|
436
|
+
console.error('📤 ExportManager: Delete pages error:', error);
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// ============================================
|
|
442
|
+
// SHARE FUNCTIONALITY
|
|
443
|
+
// ============================================
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Share exported content
|
|
447
|
+
* @param {string} content - Content to share (file path or text)
|
|
448
|
+
* @param {Object} options - Share options
|
|
449
|
+
* @returns {Promise<Object>} Share result
|
|
450
|
+
*/
|
|
451
|
+
async share(content, options = {}) {
|
|
452
|
+
const {
|
|
453
|
+
title = 'Exported from PDF',
|
|
454
|
+
message = null,
|
|
455
|
+
url = null,
|
|
456
|
+
type = 'text' // 'text', 'file'
|
|
457
|
+
} = options;
|
|
458
|
+
|
|
459
|
+
try {
|
|
460
|
+
const shareOptions = {
|
|
461
|
+
title
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
if (type === 'text') {
|
|
465
|
+
shareOptions.message = content;
|
|
466
|
+
} else if (type === 'file') {
|
|
467
|
+
shareOptions.url = Platform.OS === 'ios' ? content : `file://${content}`;
|
|
468
|
+
shareOptions.message = message;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const result = await Share.share(shareOptions);
|
|
472
|
+
console.log('📤 ExportManager: Share result:', result);
|
|
473
|
+
return result;
|
|
474
|
+
|
|
475
|
+
} catch (error) {
|
|
476
|
+
console.error('📤 ExportManager: Share error:', error);
|
|
477
|
+
throw error;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Export and share text
|
|
483
|
+
* @param {string} filePath - Path to PDF file
|
|
484
|
+
* @param {Object} options - Export options
|
|
485
|
+
* @returns {Promise<Object>} Share result
|
|
486
|
+
*/
|
|
487
|
+
async exportAndShareText(filePath, options = {}) {
|
|
488
|
+
try {
|
|
489
|
+
const text = await this.exportToText(filePath, options);
|
|
490
|
+
return await this.share(text, {
|
|
491
|
+
title: 'PDF Text Export',
|
|
492
|
+
type: 'text'
|
|
493
|
+
});
|
|
494
|
+
} catch (error) {
|
|
495
|
+
console.error('📤 ExportManager: Export and share text error:', error);
|
|
496
|
+
throw error;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Export and share image
|
|
502
|
+
* @param {string} filePath - Path to PDF file
|
|
503
|
+
* @param {number} pageNumber - Page number (1-indexed)
|
|
504
|
+
* @param {Object} options - Export options
|
|
505
|
+
* @returns {Promise<Object>} Share result
|
|
506
|
+
*/
|
|
507
|
+
async exportAndShareImage(filePath, pageNumber, options = {}) {
|
|
508
|
+
try {
|
|
509
|
+
const imagePath = await this.exportPageToImage(filePath, pageNumber, options);
|
|
510
|
+
return await this.share(imagePath, {
|
|
511
|
+
title: `PDF Page ${pageNumber}`,
|
|
512
|
+
type: 'file'
|
|
513
|
+
});
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.error('📤 ExportManager: Export and share image error:', error);
|
|
516
|
+
throw error;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// ============================================
|
|
521
|
+
// BATCH OPERATIONS
|
|
522
|
+
// ============================================
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Export multiple pages to images with progress
|
|
526
|
+
* @param {string} filePath - Path to PDF file
|
|
527
|
+
* @param {number[]} pages - Page numbers (1-indexed)
|
|
528
|
+
* @param {Object} options - Export options
|
|
529
|
+
* @param {Function} onProgress - Progress callback
|
|
530
|
+
* @returns {Promise<Array>} Array of image paths
|
|
531
|
+
*/
|
|
532
|
+
async exportPagesToImages(filePath, pages, options = {}, onProgress = null) {
|
|
533
|
+
console.log(`🖼️ [ExportManager] exportPagesToImages - START`, {
|
|
534
|
+
filePath,
|
|
535
|
+
pages,
|
|
536
|
+
pageCount: pages.length,
|
|
537
|
+
options
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
const imagePaths = [];
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
for (let i = 0; i < pages.length; i++) {
|
|
544
|
+
const pageNum = pages[i];
|
|
545
|
+
|
|
546
|
+
console.log(`📊 [ExportManager] Exporting page ${i + 1}/${pages.length} (page number: ${pageNum})`);
|
|
547
|
+
|
|
548
|
+
const imagePath = await this.exportPageToImage(filePath, pageNum, options);
|
|
549
|
+
imagePaths.push(imagePath);
|
|
550
|
+
|
|
551
|
+
console.log(`✅ [ExportManager] Page ${pageNum} exported to: ${imagePath}`);
|
|
552
|
+
|
|
553
|
+
if (onProgress) {
|
|
554
|
+
onProgress(i + 1, pages.length, imagePath);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
console.log(`✅ [ExportManager] exportPagesToImages - SUCCESS - Batch export complete: ${imagePaths.length} images`);
|
|
559
|
+
return imagePaths;
|
|
560
|
+
|
|
561
|
+
} catch (error) {
|
|
562
|
+
console.error('❌ [ExportManager] exportPagesToImages - ERROR:', error.message);
|
|
563
|
+
console.error('❌ [ExportManager] Error details:', error);
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Export pages to text with progress
|
|
570
|
+
* @param {string} filePath - Path to PDF file
|
|
571
|
+
* @param {number[]} pages - Page numbers (1-indexed)
|
|
572
|
+
* @param {Function} onProgress - Progress callback
|
|
573
|
+
* @returns {Promise<Map>} Map of page to text
|
|
574
|
+
*/
|
|
575
|
+
async exportPagesToText(filePath, pages, onProgress = null) {
|
|
576
|
+
console.log(`📤 ExportManager: Batch exporting ${pages.length} pages to text...`);
|
|
577
|
+
|
|
578
|
+
try {
|
|
579
|
+
// Convert to 0-indexed
|
|
580
|
+
const pageIndices = pages.map(p => p - 1);
|
|
581
|
+
|
|
582
|
+
const textMap = await PDFTextExtractor.extractTextFromPages(filePath, pageIndices);
|
|
583
|
+
|
|
584
|
+
if (onProgress) {
|
|
585
|
+
onProgress(textMap.size, pages.length);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return textMap;
|
|
589
|
+
|
|
590
|
+
} catch (error) {
|
|
591
|
+
console.error('📤 ExportManager: Batch text export error:', error);
|
|
592
|
+
throw error;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// ============================================
|
|
597
|
+
// UTILITY METHODS
|
|
598
|
+
// ============================================
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Get export capabilities
|
|
602
|
+
* @returns {Object} Capabilities object
|
|
603
|
+
*/
|
|
604
|
+
getCapabilities() {
|
|
605
|
+
return {
|
|
606
|
+
exportToText: PDFTextExtractor.isTextExtractionAvailable(),
|
|
607
|
+
exportToImages: this.isNativeAvailable,
|
|
608
|
+
mergePDFs: this.isNativeAvailable,
|
|
609
|
+
splitPDF: this.isNativeAvailable,
|
|
610
|
+
extractPages: this.isNativeAvailable,
|
|
611
|
+
rotatePages: this.isNativeAvailable,
|
|
612
|
+
deletePages: this.isNativeAvailable,
|
|
613
|
+
share: true // Share API is always available
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Get module information
|
|
619
|
+
* @returns {Object} Module info
|
|
620
|
+
*/
|
|
621
|
+
getModuleInfo() {
|
|
622
|
+
return {
|
|
623
|
+
isAvailable: this.isNativeAvailable,
|
|
624
|
+
platform: Platform.OS,
|
|
625
|
+
version: PDFExporter?.VERSION || 'N/A',
|
|
626
|
+
capabilities: this.getCapabilities()
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Estimate export time
|
|
632
|
+
* @param {number} pageCount - Number of pages to export
|
|
633
|
+
* @param {string} format - Export format
|
|
634
|
+
* @returns {Object} Time estimate
|
|
635
|
+
*/
|
|
636
|
+
estimateExportTime(pageCount, format = ExportFormat.TEXT) {
|
|
637
|
+
let msPerPage;
|
|
638
|
+
|
|
639
|
+
switch (format) {
|
|
640
|
+
case ExportFormat.TEXT:
|
|
641
|
+
msPerPage = 80; // Text extraction avg
|
|
642
|
+
break;
|
|
643
|
+
case ExportFormat.JPEG:
|
|
644
|
+
case ExportFormat.PNG:
|
|
645
|
+
msPerPage = 200; // Image rendering avg
|
|
646
|
+
break;
|
|
647
|
+
default:
|
|
648
|
+
msPerPage = 100;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const totalMs = pageCount * msPerPage;
|
|
652
|
+
const seconds = Math.round(totalMs / 1000);
|
|
653
|
+
|
|
654
|
+
return {
|
|
655
|
+
milliseconds: totalMs,
|
|
656
|
+
seconds,
|
|
657
|
+
formatted: seconds < 60
|
|
658
|
+
? `${seconds} seconds`
|
|
659
|
+
: `${Math.round(seconds / 60)} minutes`
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// ============================================
|
|
664
|
+
// FALLBACK METHODS
|
|
665
|
+
// ============================================
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Fallback image export (if native not available)
|
|
669
|
+
*/
|
|
670
|
+
async exportToImagesFallback(filePath, options) {
|
|
671
|
+
console.warn('📤 ExportManager: Using fallback image export');
|
|
672
|
+
console.warn('📤 Note: Fallback export has limitations');
|
|
673
|
+
|
|
674
|
+
// In a real implementation, this could use:
|
|
675
|
+
// 1. Screenshot-based export
|
|
676
|
+
// 2. Canvas-based rendering
|
|
677
|
+
// 3. Server-side conversion
|
|
678
|
+
|
|
679
|
+
throw new Error('Native export module required for image export');
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Create singleton instance
|
|
684
|
+
const exportManager = new ExportManager();
|
|
685
|
+
|
|
686
|
+
export default exportManager;
|
|
687
|
+
|