react-native-pdf-jsi 1.0.2 → 2.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 +132 -10
- package/android/src/main/java/org/wonday/pdf/PDFNativeCacheManager.java +748 -0
- package/ios/RNPDFPdf/PDFJSIManager.h +15 -0
- package/ios/RNPDFPdf/PDFJSIManager.m +581 -0
- package/ios/RNPDFPdf/PDFNativeCacheManager.h +20 -0
- package/ios/RNPDFPdf/PDFNativeCacheManager.m +743 -0
- package/package.json +35 -7
- package/src/EnhancedPdfView.js +52 -2
- package/src/PDFJSI.js +247 -3
- package/src/examples/PDFJSIExample.js +463 -195
- package/src/hooks/usePDFJSI.js +53 -0
package/package.json
CHANGED
|
@@ -1,28 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-pdf-jsi",
|
|
3
|
-
"version": "
|
|
4
|
-
"summary": "
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"summary": "High-performance React Native PDF viewer with JSI acceleration - up to 80x faster than traditional bridge",
|
|
5
|
+
"description": "🚀 Ultra-fast React Native PDF viewer with JSI (JavaScript Interface) integration for maximum performance. Features lazy loading, smart caching, progressive loading, and zero-bridge overhead operations. Perfect for large PDF files with 30-day persistent cache and advanced memory optimization. Supports iOS, Android, and Windows platforms.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"typings": "./index.d.ts",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/126punith/react-native-pdf
|
|
10
|
+
"url": "git+https://github.com/126punith/react-native-enhanced-pdf.git"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
13
|
+
"react-native-pdf",
|
|
14
|
+
"react-native-pdf-viewer",
|
|
15
|
+
"react-native-pdf-jsi",
|
|
16
|
+
"react-native-pdf-enhanced",
|
|
17
|
+
"pdf-viewer",
|
|
18
|
+
"pdf-reader",
|
|
19
|
+
"pdf-view",
|
|
13
20
|
"react-component",
|
|
14
21
|
"react-native",
|
|
22
|
+
"react-native-module",
|
|
23
|
+
"react-native-library",
|
|
15
24
|
"android",
|
|
16
25
|
"ios",
|
|
26
|
+
"windows",
|
|
17
27
|
"pdf",
|
|
18
28
|
"view",
|
|
19
29
|
"viewer",
|
|
20
30
|
"jsi",
|
|
31
|
+
"javascript-interface",
|
|
21
32
|
"performance",
|
|
22
33
|
"enhanced",
|
|
23
34
|
"native",
|
|
24
35
|
"bridge",
|
|
25
|
-
"high-performance"
|
|
36
|
+
"high-performance",
|
|
37
|
+
"fast-pdf",
|
|
38
|
+
"lazy-loading",
|
|
39
|
+
"smart-caching",
|
|
40
|
+
"progressive-loading",
|
|
41
|
+
"memory-optimization",
|
|
42
|
+
"zero-bridge",
|
|
43
|
+
"native-module",
|
|
44
|
+
"cross-platform",
|
|
45
|
+
"mobile",
|
|
46
|
+
"document-viewer",
|
|
47
|
+
"pdf-renderer",
|
|
48
|
+
"pdf-display",
|
|
49
|
+
"large-files",
|
|
50
|
+
"optimization",
|
|
51
|
+
"caching",
|
|
52
|
+
"persistent-cache",
|
|
53
|
+
"react-native-pdf-jsi-enhanced"
|
|
26
54
|
],
|
|
27
55
|
"author": {
|
|
28
56
|
"name": "Punith M",
|
|
@@ -30,9 +58,9 @@
|
|
|
30
58
|
"url": "https://github.com/126punith"
|
|
31
59
|
},
|
|
32
60
|
"license": "MIT",
|
|
33
|
-
|
|
61
|
+
"homepage": "https://github.com/126punith/react-native-enhanced-pdf",
|
|
34
62
|
"bugs": {
|
|
35
|
-
"url": "https://github.com/126punith/react-native-pdf
|
|
63
|
+
"url": "https://github.com/126punith/react-native-enhanced-pdf/issues"
|
|
36
64
|
},
|
|
37
65
|
"dependencies": {
|
|
38
66
|
"crypto-js": "4.2.0",
|
package/src/EnhancedPdfView.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright (c) 2025-present,
|
|
3
|
-
* Enhanced PDF View with JSI integration
|
|
2
|
+
* Copyright (c) 2025-present, Enhanced PDF View with JSI
|
|
4
3
|
* All rights reserved.
|
|
5
4
|
*
|
|
6
5
|
* Enhanced PDF View component that automatically uses JSI when available
|
|
@@ -273,6 +272,57 @@ export default class EnhancedPdfView extends Component {
|
|
|
273
272
|
}
|
|
274
273
|
};
|
|
275
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Lazy load pages for large PDF files
|
|
277
|
+
*/
|
|
278
|
+
lazyLoadPages = async (currentPage, preloadRadius = 3, totalPages = null) => {
|
|
279
|
+
try {
|
|
280
|
+
const pdfId = `pdf_${Date.now()}`;
|
|
281
|
+
const result = await PDFJSI.lazyLoadPages(pdfId, currentPage, preloadRadius, totalPages);
|
|
282
|
+
|
|
283
|
+
if (result.success) {
|
|
284
|
+
console.log(`📱 EnhancedPdfView: Lazy loaded pages around ${currentPage} via JSI`);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return result;
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.error('📱 EnhancedPdfView: JSI lazy load error:', error);
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Progressive loading for large PDF files
|
|
296
|
+
*/
|
|
297
|
+
progressiveLoadPages = async (startPage = 1, batchSize = 5, onProgress = null) => {
|
|
298
|
+
try {
|
|
299
|
+
const pdfId = `pdf_${Date.now()}`;
|
|
300
|
+
const result = await PDFJSI.progressiveLoadPages(pdfId, startPage, batchSize, onProgress);
|
|
301
|
+
|
|
302
|
+
console.log(`📱 EnhancedPdfView: Progressive loaded ${result.totalLoaded} pages via JSI`);
|
|
303
|
+
return result;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
console.error('📱 EnhancedPdfView: JSI progressive load error:', error);
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Smart caching for frequently accessed pages
|
|
312
|
+
*/
|
|
313
|
+
smartCacheFrequentPages = async (frequentPages = []) => {
|
|
314
|
+
try {
|
|
315
|
+
const pdfId = `pdf_${Date.now()}`;
|
|
316
|
+
const result = await PDFJSI.smartCacheFrequentPages(pdfId, frequentPages);
|
|
317
|
+
|
|
318
|
+
console.log(`📱 EnhancedPdfView: Smart cached ${result.successfulCaches}/${result.totalPages} frequent pages via JSI`);
|
|
319
|
+
return result;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error('📱 EnhancedPdfView: JSI smart cache error:', error);
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
|
|
276
326
|
render() {
|
|
277
327
|
const { isJSIAvailable, jsiInitialized, renderMode } = this.state;
|
|
278
328
|
|
package/src/PDFJSI.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright (c) 2025-present,
|
|
3
|
-
* Enhanced PDF JSI JavaScript Bridge with high-performance operations
|
|
2
|
+
* Copyright (c) 2025-present, Enhanced PDF JSI JavaScript Bridge
|
|
4
3
|
* All rights reserved.
|
|
5
4
|
*
|
|
6
5
|
* JavaScript interface for high-performance PDF operations via JSI
|
|
@@ -495,6 +494,248 @@ class PDFJSIManager {
|
|
|
495
494
|
this.performanceMetrics.clear();
|
|
496
495
|
console.log('📱 PDFJSI: Performance history cleared');
|
|
497
496
|
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Lazy load PDF pages for large files
|
|
500
|
+
* @param {string} pdfId - PDF identifier
|
|
501
|
+
* @param {number} currentPage - Current page number
|
|
502
|
+
* @param {number} preloadRadius - Number of pages to preload around current page
|
|
503
|
+
* @param {number} totalPages - Total number of pages in PDF
|
|
504
|
+
* @returns {Promise<Object>} Lazy load result
|
|
505
|
+
*/
|
|
506
|
+
async lazyLoadPages(pdfId, currentPage, preloadRadius = 3, totalPages = null) {
|
|
507
|
+
if (!this.isJSIAvailable) {
|
|
508
|
+
throw new Error('JSI not available - falling back to bridge mode');
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const startTime = performance.now();
|
|
512
|
+
|
|
513
|
+
try {
|
|
514
|
+
console.log(`📱 PDFJSI: Lazy loading pages around page ${currentPage} for PDF ${pdfId}`);
|
|
515
|
+
|
|
516
|
+
// Calculate pages to preload
|
|
517
|
+
const startPage = Math.max(1, currentPage - preloadRadius);
|
|
518
|
+
const endPage = totalPages ? Math.min(totalPages, currentPage + preloadRadius) : currentPage + preloadRadius;
|
|
519
|
+
|
|
520
|
+
// Preload pages in background
|
|
521
|
+
const preloadResult = await this.preloadPagesDirect(pdfId, startPage, endPage);
|
|
522
|
+
|
|
523
|
+
const endTime = performance.now();
|
|
524
|
+
const lazyLoadTime = endTime - startTime;
|
|
525
|
+
|
|
526
|
+
// Track performance
|
|
527
|
+
this.trackPerformance('lazyLoadPages', lazyLoadTime, {
|
|
528
|
+
pdfId,
|
|
529
|
+
currentPage,
|
|
530
|
+
startPage,
|
|
531
|
+
endPage,
|
|
532
|
+
preloadRadius,
|
|
533
|
+
success: preloadResult
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
console.log(`📱 PDFJSI: Lazy loaded pages ${startPage}-${endPage} in ${lazyLoadTime.toFixed(2)}ms`);
|
|
537
|
+
|
|
538
|
+
return {
|
|
539
|
+
success: preloadResult,
|
|
540
|
+
currentPage,
|
|
541
|
+
preloadedRange: { startPage, endPage },
|
|
542
|
+
lazyLoadTime,
|
|
543
|
+
preloadRadius
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
} catch (error) {
|
|
547
|
+
const endTime = performance.now();
|
|
548
|
+
const lazyLoadTime = endTime - startTime;
|
|
549
|
+
|
|
550
|
+
console.error(`📱 PDFJSI: Error lazy loading pages in ${lazyLoadTime.toFixed(2)}ms:`, error);
|
|
551
|
+
|
|
552
|
+
this.trackPerformance('lazyLoadPages', lazyLoadTime, {
|
|
553
|
+
pdfId,
|
|
554
|
+
currentPage,
|
|
555
|
+
preloadRadius,
|
|
556
|
+
success: false,
|
|
557
|
+
error: error.message
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
throw error;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Progressive loading for large PDF files
|
|
566
|
+
* @param {string} pdfId - PDF identifier
|
|
567
|
+
* @param {number} startPage - Starting page number
|
|
568
|
+
* @param {number} batchSize - Number of pages to load in each batch
|
|
569
|
+
* @param {Function} onProgress - Progress callback function
|
|
570
|
+
* @returns {Promise<Object>} Progressive load result
|
|
571
|
+
*/
|
|
572
|
+
async progressiveLoadPages(pdfId, startPage = 1, batchSize = 5, onProgress = null) {
|
|
573
|
+
if (!this.isJSIAvailable) {
|
|
574
|
+
throw new Error('JSI not available - falling back to bridge mode');
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const startTime = performance.now();
|
|
578
|
+
|
|
579
|
+
try {
|
|
580
|
+
console.log(`📱 PDFJSI: Progressive loading starting from page ${startPage} for PDF ${pdfId}`);
|
|
581
|
+
|
|
582
|
+
let currentPage = startPage;
|
|
583
|
+
let totalLoaded = 0;
|
|
584
|
+
const loadResults = [];
|
|
585
|
+
|
|
586
|
+
// Load pages in batches
|
|
587
|
+
while (true) {
|
|
588
|
+
const batchStartPage = currentPage;
|
|
589
|
+
const batchEndPage = currentPage + batchSize - 1;
|
|
590
|
+
|
|
591
|
+
console.log(`📱 PDFJSI: Loading batch ${batchStartPage}-${batchEndPage}`);
|
|
592
|
+
|
|
593
|
+
const batchResult = await this.preloadPagesDirect(pdfId, batchStartPage, batchEndPage);
|
|
594
|
+
|
|
595
|
+
if (!batchResult) {
|
|
596
|
+
console.log(`📱 PDFJSI: Batch loading failed at page ${currentPage}`);
|
|
597
|
+
break;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
loadResults.push({
|
|
601
|
+
startPage: batchStartPage,
|
|
602
|
+
endPage: batchEndPage,
|
|
603
|
+
success: batchResult
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
totalLoaded += batchSize;
|
|
607
|
+
currentPage += batchSize;
|
|
608
|
+
|
|
609
|
+
// Call progress callback if provided
|
|
610
|
+
if (onProgress && typeof onProgress === 'function') {
|
|
611
|
+
onProgress({
|
|
612
|
+
currentPage,
|
|
613
|
+
totalLoaded,
|
|
614
|
+
batchStartPage,
|
|
615
|
+
batchEndPage,
|
|
616
|
+
success: batchResult
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Small delay between batches to prevent blocking
|
|
621
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const endTime = performance.now();
|
|
625
|
+
const progressiveLoadTime = endTime - startTime;
|
|
626
|
+
|
|
627
|
+
// Track performance
|
|
628
|
+
this.trackPerformance('progressiveLoadPages', progressiveLoadTime, {
|
|
629
|
+
pdfId,
|
|
630
|
+
startPage,
|
|
631
|
+
batchSize,
|
|
632
|
+
totalLoaded,
|
|
633
|
+
batchesLoaded: loadResults.length
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
console.log(`📱 PDFJSI: Progressive loading completed: ${totalLoaded} pages in ${progressiveLoadTime.toFixed(2)}ms`);
|
|
637
|
+
|
|
638
|
+
return {
|
|
639
|
+
success: true,
|
|
640
|
+
totalLoaded,
|
|
641
|
+
batchesLoaded: loadResults.length,
|
|
642
|
+
loadResults,
|
|
643
|
+
progressiveLoadTime
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
} catch (error) {
|
|
647
|
+
const endTime = performance.now();
|
|
648
|
+
const progressiveLoadTime = endTime - startTime;
|
|
649
|
+
|
|
650
|
+
console.error(`📱 PDFJSI: Error in progressive loading in ${progressiveLoadTime.toFixed(2)}ms:`, error);
|
|
651
|
+
|
|
652
|
+
this.trackPerformance('progressiveLoadPages', progressiveLoadTime, {
|
|
653
|
+
pdfId,
|
|
654
|
+
startPage,
|
|
655
|
+
batchSize,
|
|
656
|
+
success: false,
|
|
657
|
+
error: error.message
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
throw error;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Smart caching for frequently accessed pages
|
|
666
|
+
* @param {string} pdfId - PDF identifier
|
|
667
|
+
* @param {Array<number>} frequentPages - Array of frequently accessed page numbers
|
|
668
|
+
* @returns {Promise<Object>} Smart cache result
|
|
669
|
+
*/
|
|
670
|
+
async smartCacheFrequentPages(pdfId, frequentPages = []) {
|
|
671
|
+
if (!this.isJSIAvailable) {
|
|
672
|
+
throw new Error('JSI not available - falling back to bridge mode');
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const startTime = performance.now();
|
|
676
|
+
|
|
677
|
+
try {
|
|
678
|
+
console.log(`📱 PDFJSI: Smart caching ${frequentPages.length} frequent pages for PDF ${pdfId}`);
|
|
679
|
+
|
|
680
|
+
const cacheResults = [];
|
|
681
|
+
|
|
682
|
+
// Cache each frequent page
|
|
683
|
+
for (const pageNumber of frequentPages) {
|
|
684
|
+
try {
|
|
685
|
+
const cacheResult = await this.preloadPagesDirect(pdfId, pageNumber, pageNumber);
|
|
686
|
+
cacheResults.push({
|
|
687
|
+
pageNumber,
|
|
688
|
+
success: cacheResult
|
|
689
|
+
});
|
|
690
|
+
} catch (error) {
|
|
691
|
+
console.warn(`📱 PDFJSI: Failed to cache page ${pageNumber}:`, error);
|
|
692
|
+
cacheResults.push({
|
|
693
|
+
pageNumber,
|
|
694
|
+
success: false,
|
|
695
|
+
error: error.message
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const endTime = performance.now();
|
|
701
|
+
const smartCacheTime = endTime - startTime;
|
|
702
|
+
|
|
703
|
+
const successfulCaches = cacheResults.filter(result => result.success).length;
|
|
704
|
+
|
|
705
|
+
// Track performance
|
|
706
|
+
this.trackPerformance('smartCacheFrequentPages', smartCacheTime, {
|
|
707
|
+
pdfId,
|
|
708
|
+
totalPages: frequentPages.length,
|
|
709
|
+
successfulCaches,
|
|
710
|
+
cacheResults
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
console.log(`📱 PDFJSI: Smart caching completed: ${successfulCaches}/${frequentPages.length} pages cached in ${smartCacheTime.toFixed(2)}ms`);
|
|
714
|
+
|
|
715
|
+
return {
|
|
716
|
+
success: true,
|
|
717
|
+
totalPages: frequentPages.length,
|
|
718
|
+
successfulCaches,
|
|
719
|
+
cacheResults,
|
|
720
|
+
smartCacheTime
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
} catch (error) {
|
|
724
|
+
const endTime = performance.now();
|
|
725
|
+
const smartCacheTime = endTime - startTime;
|
|
726
|
+
|
|
727
|
+
console.error(`📱 PDFJSI: Error in smart caching in ${smartCacheTime.toFixed(2)}ms:`, error);
|
|
728
|
+
|
|
729
|
+
this.trackPerformance('smartCacheFrequentPages', smartCacheTime, {
|
|
730
|
+
pdfId,
|
|
731
|
+
totalPages: frequentPages.length,
|
|
732
|
+
success: false,
|
|
733
|
+
error: error.message
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
throw error;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
498
739
|
}
|
|
499
740
|
|
|
500
741
|
// Create singleton instance
|
|
@@ -515,5 +756,8 @@ export const {
|
|
|
515
756
|
setRenderQuality,
|
|
516
757
|
getJSIStats,
|
|
517
758
|
getPerformanceHistory,
|
|
518
|
-
clearPerformanceHistory
|
|
759
|
+
clearPerformanceHistory,
|
|
760
|
+
lazyLoadPages,
|
|
761
|
+
progressiveLoadPages,
|
|
762
|
+
smartCacheFrequentPages
|
|
519
763
|
} = pdfJSIManager;
|