CPDFAnnotationsExample.tsx 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /**
  2. * Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
  3. *
  4. * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  5. * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  6. * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  7. * This notice may not be removed from this file.
  8. */
  9. import React, { useState, useRef } from 'react';
  10. import { Image, Platform, StyleSheet, Text, View } from 'react-native';
  11. import PDFReaderContext, { CPDFReaderView, ComPDFKit, CPDFToolbarAction, CPDFAnnotation } from '@compdfkit_pdf_sdk/react_native';
  12. import { useNavigation, useRoute, RouteProp } from '@react-navigation/native';
  13. import { HeaderBackButton } from '@react-navigation/elements';
  14. import { MenuProvider, Menu, MenuTrigger, MenuOptions, MenuOption } from 'react-native-popup-menu';
  15. import { SafeAreaView } from 'react-native-safe-area-context';
  16. import DocumentPicker from 'react-native-document-picker';
  17. import { CPDFAnnotationListScreen } from './screens/CPDFAnnotationListScreen';
  18. type RootStackParamList = {
  19. CPDFReaderViewExample: { document?: string };
  20. };
  21. type CPDFReaderViewExampleScreenRouteProp = RouteProp<
  22. RootStackParamList,
  23. 'CPDFReaderViewExample'
  24. >;
  25. const CPDFAnnotationsExampleScreen = () => {
  26. const pdfReaderRef = useRef<CPDFReaderView>(null);
  27. const navigation = useNavigation();
  28. const route = useRoute<CPDFReaderViewExampleScreenRouteProp>();
  29. const [annotationModalVisible, setAnnotationModalVisible] = useState(false);
  30. const [annotationData, setAnnotationData] = useState<CPDFAnnotation[]>([]);
  31. const [samplePDF] = useState(
  32. route.params?.document || (Platform.OS === 'android'
  33. ? 'file:///android_asset/PDF_Document.pdf'
  34. : 'PDF_Document.pdf')
  35. );
  36. const handleSave = async () => {
  37. if (pdfReaderRef.current) {
  38. const success = await pdfReaderRef.current.save();
  39. if (success) {
  40. console.log('ComPDFKitRN save() : Document saved successfully');
  41. } else {
  42. console.log('ComPDFKitRN save() : Failed to save document');
  43. }
  44. }
  45. };
  46. const menuOptions = [
  47. 'openDocument',
  48. 'Save',
  49. 'Remove All Annotations',
  50. 'Import Annotations 1',
  51. 'Import Annotations 2',
  52. 'Export Annotations',
  53. 'Get Annotations'
  54. ];
  55. const handleMenuItemPress = async (action: string) => {
  56. switch (action) {
  57. case 'Save':
  58. handleSave();
  59. break;
  60. case 'Remove All Annotations':
  61. const removeResult = await pdfReaderRef.current?._pdfDocument.removeAllAnnotations();
  62. console.log('ComPDFKitRN removeAllAnnotations:', removeResult);
  63. break;
  64. case 'Import Annotations 1':
  65. try {
  66. // Select an xfdf file from the public directory and import it into the current document
  67. const pickerResult = DocumentPicker.pick({
  68. type: [DocumentPicker.types.allFiles],
  69. copyTo: 'cachesDirectory'
  70. });
  71. pickerResult.then(async (res) => {
  72. const file = res[0];
  73. console.log('fileUri:', file?.uri);
  74. console.log('fileCopyUri:', file?.fileCopyUri);
  75. console.log('fileType:', file?.type);
  76. const path = file!!.fileCopyUri!!
  77. if (!path?.endsWith('xml') && !path?.endsWith('xfdf')) {
  78. console.log('ComPDFKitRN please select xfdf format file');
  79. return;
  80. }
  81. const importResult = await pdfReaderRef.current?._pdfDocument.importAnnotations(path);
  82. console.log('ComPDFKitRN importAnnotations:', importResult);
  83. })
  84. } catch (err) {
  85. }
  86. break;
  87. case 'Import Annotations 2':
  88. // Android
  89. // import xfdf file from android assets directory
  90. const testXfdf = Platform.OS === 'android'
  91. ? 'file:///android_asset/test.xfdf'
  92. : 'test.xfdf'
  93. // import xfdf file from file path
  94. // const testXfdf = '/data/user/0/com.compdfkit.reactnative.example/xxx/xxx.xfdf';
  95. const importResult = await pdfReaderRef.current?._pdfDocument.importAnnotations(testXfdf);
  96. console.log('ComPDFKitRN importAnnotations:', importResult);
  97. break;
  98. case 'Export Annotations':
  99. const exportXfdfFilePath = await pdfReaderRef.current?._pdfDocument.exportAnnotations();
  100. console.log('ComPDFKitRN exportAnnotations:', exportXfdfFilePath);
  101. break;
  102. case 'openDocument':
  103. const document = await ComPDFKit.pickFile();
  104. if (document) {
  105. await pdfReaderRef.current?._pdfDocument.open(document);
  106. }
  107. break;
  108. case 'Get Annotations':
  109. const pageCount = await pdfReaderRef!.current!._pdfDocument.getPageCount();
  110. let allAnnotations: CPDFAnnotation[] = [];
  111. for (let i = 0; i < pageCount; i++) {
  112. const page = pdfReaderRef?.current?._pdfDocument.pageAtIndex(i);
  113. const annotations = await page?.getAnnotations();
  114. if (annotations) {
  115. allAnnotations = allAnnotations.concat(annotations);
  116. }
  117. console.log(JSON.stringify(annotations, null, 2));
  118. }
  119. setAnnotationData(allAnnotations);
  120. setAnnotationModalVisible(true);
  121. break;
  122. default:
  123. break;
  124. }
  125. };
  126. const handleBack = () => {
  127. navigation.goBack();
  128. };
  129. const renderToolbar = () => {
  130. return (
  131. <View style={styles.toolbar}>
  132. <HeaderBackButton onPress={handleBack} />
  133. <Text style={styles.toolbarTitle}>Annotations Example</Text>
  134. <Menu>
  135. <MenuTrigger>
  136. <Image source={require('../assets/more.png')} style={{ width: 24, height: 24, marginEnd: 8 }} />
  137. </MenuTrigger>
  138. <MenuOptions>
  139. {menuOptions.map((option, index) => (
  140. <MenuOption key={index} onSelect={() => handleMenuItemPress(option)}>
  141. <Text style={styles.menuOption}>{option}</Text>
  142. </MenuOption>
  143. ))}
  144. </MenuOptions>
  145. </Menu>
  146. </View>
  147. );
  148. };
  149. return (
  150. <PDFReaderContext.Provider value={pdfReaderRef.current}>
  151. <MenuProvider>
  152. <SafeAreaView style={{ flex: 1 }}>
  153. <View style={{ flex: 1 }}>
  154. {renderToolbar()}
  155. <CPDFReaderView
  156. ref={pdfReaderRef}
  157. document={samplePDF}
  158. configuration={ComPDFKit.getDefaultConfig({
  159. toolbarConfig: {
  160. iosLeftBarAvailableActions: [
  161. CPDFToolbarAction.THUMBNAIL
  162. ]
  163. }
  164. })} />
  165. <CPDFAnnotationListScreen
  166. visible={annotationModalVisible}
  167. annotations={annotationData}
  168. onClose={() => setAnnotationModalVisible(false)} />
  169. </View>
  170. </SafeAreaView>
  171. </MenuProvider>
  172. </PDFReaderContext.Provider>
  173. );
  174. };
  175. const styles = StyleSheet.create({
  176. toolbar: {
  177. height: 56,
  178. flexDirection: 'row',
  179. alignItems: 'center',
  180. justifyContent: 'flex-start',
  181. backgroundColor: '#FAFCFF',
  182. paddingHorizontal: 4,
  183. },
  184. toolbarButton: {
  185. padding: 8,
  186. },
  187. toolbarTitle: {
  188. flex: 1,
  189. color: 'black',
  190. fontSize: 16,
  191. fontWeight: 'bold',
  192. marginStart: 8
  193. },
  194. menuOption: {
  195. padding: 8,
  196. fontSize: 14,
  197. color: 'black',
  198. },
  199. });
  200. export default CPDFAnnotationsExampleScreen;