cpdf_document.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // Copyright © 2014-2025 PDF Technologies, Inc. All Rights Reserved.
  2. //
  3. // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
  4. // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
  5. // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
  6. // This notice may not be removed from this file.
  7. import 'package:compdfkit_flutter/configuration/cpdf_options.dart';
  8. import 'package:compdfkit_flutter/document/cpdf_watermark.dart';
  9. import 'package:flutter/services.dart';
  10. import 'package:flutter/widgets.dart';
  11. import '../compdfkit.dart';
  12. import '../util/cpdf_uuid_util.dart';
  13. /// A class to handle PDF documents without using [CPDFReaderWidget]
  14. ///
  15. /// example:
  16. /// ```dart
  17. /// var document = CPDFDocument();
  18. /// document.open('pdf file path', 'password');
  19. ///
  20. /// /// get pdf document info.
  21. /// var info = await document.getInfo();
  22. ///
  23. /// /// get pdf document file name.
  24. /// var fileName = await document.getFileName();
  25. /// ```
  26. class CPDFDocument {
  27. late final MethodChannel _channel;
  28. bool _isValid = false;
  29. get isValid => _isValid;
  30. static Future<CPDFDocument> createInstance() async {
  31. var id = CpdfUuidUtil.generateShortUniqueId();
  32. bool success = await ComPDFKit.createDocumentInstance(id);
  33. if (!success) {
  34. throw Exception('Failed to create document instance');
  35. }
  36. return CPDFDocument._(id);
  37. }
  38. CPDFDocument._(String id) {
  39. _channel = MethodChannel('com.compdfkit.flutter.document_$id');
  40. }
  41. CPDFDocument.withController(int viewId)
  42. : _channel = MethodChannel('com.compdfkit.flutter.document_$viewId'),
  43. _isValid = true;
  44. Future<CPDFDocumentError> open(String filePath, String password) async {
  45. try{
  46. var error = await _channel.invokeMethod(
  47. 'open_document', {'filePath': filePath, 'password': password});
  48. var type = CPDFDocumentError.values.where((e) => e.name == error).first;
  49. if(type == CPDFDocumentError.success){
  50. _isValid = true;
  51. }
  52. return type;
  53. } on PlatformException {
  54. return CPDFDocumentError.unknown;
  55. }
  56. }
  57. /// Gets the file name of the PDF document.
  58. ///
  59. /// example:
  60. /// ```dart
  61. /// var fileName = await document.getFileName();
  62. /// ```
  63. Future<String> getFileName() async {
  64. return await _channel.invokeMethod('get_file_name');
  65. }
  66. /// Checks if the PDF document is encrypted.
  67. ///
  68. /// example:
  69. /// ```dart
  70. /// var isEncrypted = await document.isEncrypted();
  71. /// ```
  72. Future<bool> isEncrypted() async {
  73. return await _channel.invokeMethod('is_encrypted');
  74. }
  75. /// Checks if the PDF document is an image document.
  76. /// This is a time-consuming operation that depends on the document size.
  77. ///
  78. /// example:
  79. /// ```dart
  80. /// var isImageDoc = await document.isImageDoc();
  81. /// ```
  82. Future<bool> isImageDoc() async {
  83. return await _channel.invokeMethod('is_image_doc');
  84. }
  85. /// Gets the current document's permissions. There are three types of permissions:
  86. /// No restrictions: [CPDFDocumentPermissions.none]
  87. /// If the document has an open password and an owner password,
  88. /// using the open password will grant [CPDFDocumentPermissions.user] permissions,
  89. /// and using the owner password will grant [CPDFDocumentPermissions.owner] permissions.
  90. ///
  91. /// example:
  92. /// ```dart
  93. /// var permissions = await document.getPermissions();
  94. /// ```
  95. Future<CPDFDocumentPermissions> getPermissions() async {
  96. int permissionId = await _channel.invokeMethod('get_permissions');
  97. return CPDFDocumentPermissions.values[permissionId];
  98. }
  99. /// Check if owner permissions are unlocked
  100. ///
  101. /// example:
  102. /// ```dart
  103. /// var isUnlocked = await document.checkOwnerUnlocked();
  104. /// ```
  105. Future<bool> checkOwnerUnlocked() async {
  106. return await _channel.invokeMethod('check_owner_unlocked');
  107. }
  108. /// Whether the owner password is correct.
  109. ///
  110. /// example:
  111. /// ```dart
  112. /// var isCorrect = await document.checkOwnerPassword('password');
  113. /// ```
  114. Future<bool> checkOwnerPassword(String password) async {
  115. return await _channel.invokeMethod('check_owner_password',
  116. {'password': password});
  117. }
  118. /// Check the document for modifications
  119. ///
  120. /// example:
  121. /// ```dart
  122. /// bool hasChange = await document.hasChange();
  123. /// ```
  124. Future<bool> hasChange() async {
  125. return await _channel.invokeMethod('has_change');
  126. }
  127. /// Imports annotations from the specified XFDF file into the current PDF document.
  128. ///
  129. /// **Parameters:**<br/>
  130. /// xfdfFile - Path of the XFDF file to be imported.
  131. ///
  132. /// **example:**
  133. /// ```dart
  134. /// bool result = await document.importAnnotations(xxx.xfdf);
  135. /// ```
  136. ///
  137. /// **Returns:**
  138. /// true if the import is successful; otherwise, false.
  139. Future<bool> importAnnotations(String xfdfFile) async {
  140. return await _channel.invokeMethod('import_annotations', xfdfFile);
  141. }
  142. /// Exports annotations from the current PDF document to an XFDF file.
  143. ///
  144. /// **example:**
  145. /// ```dart
  146. /// String xfdfPath = await document.exportAnnotations();
  147. /// ```
  148. ///
  149. /// Returns:
  150. /// The path of the XFDF file if export is successful; an empty string if the export fails.
  151. Future<String> exportAnnotations() async {
  152. return await _channel.invokeMethod('export_annotations');
  153. }
  154. /// Delete all comments in the current document
  155. ///
  156. /// example:
  157. /// ```dart
  158. /// bool result = await document.removeAllAnnotations();
  159. /// ```
  160. Future<bool> removeAllAnnotations() async {
  161. return await _channel.invokeMethod('remove_all_annotations');
  162. }
  163. /// Get the total number of pages in the current document
  164. ///
  165. /// example:
  166. /// ```dart
  167. /// int pageCount = await document.getPageCount();
  168. /// ```
  169. Future<int> getPageCount() async {
  170. return await _channel.invokeMethod('get_page_count');
  171. }
  172. /// Save document
  173. ///
  174. /// example:
  175. /// ```dart
  176. /// bool result = await _controller.save();
  177. /// ```
  178. /// Return value: **true** if the save is successful,
  179. /// **false** if the save fails.
  180. Future<bool> save() async {
  181. return await _channel.invokeMethod('save');
  182. }
  183. /// Saves the document to the specified directory.
  184. ///
  185. /// Example usage:
  186. /// ```dart
  187. /// await controller.document.saveAs('data/your_package_name/files/xxx.pdf')
  188. /// ```
  189. /// - [savePath] Specifies the path where the document should be saved.
  190. /// On Android, both file paths and URIs are supported. For example:
  191. /// - File path: `/data/user/0/com.compdfkit.flutter.example/cache/temp/PDF_Document.pdf`
  192. /// - URI: `content://media/external/file/1000045118`
  193. /// - [removeSecurity] Whether to remove the document's password.
  194. /// - [fontSubSet] Whether to embed the font subset when saving the PDF.
  195. /// This will affect how text appears in other PDF software. This is a time-consuming operation.
  196. Future<bool> saveAs(String savePath, {
  197. bool removeSecurity = false,
  198. bool fontSubSet = true
  199. }) async {
  200. try {
  201. return await _channel.invokeMethod('save_as', {
  202. 'save_path' : savePath,
  203. 'remove_security' : removeSecurity,
  204. 'font_sub_set' : fontSubSet
  205. });
  206. } on PlatformException catch (e) {
  207. debugPrint(e.details);
  208. return false;
  209. } catch (e) {
  210. return false;
  211. }
  212. }
  213. /// Invokes the system's print service to print the current document.
  214. ///
  215. /// example:
  216. /// ```dart
  217. /// await document.printDocument();
  218. /// ```
  219. Future<void> printDocument() async {
  220. await _channel.invokeMethod('print');
  221. }
  222. /// Remove the user password and owner permission password
  223. /// set in the document, and perform an incremental save.
  224. ///
  225. /// example:
  226. /// ```dart
  227. /// bool result = await document.removePassword();
  228. /// ```
  229. Future<bool> removePassword() async{
  230. try{
  231. return await _channel.invokeMethod('remove_password');
  232. } on PlatformException catch (e) {
  233. debugPrint(e.message);
  234. return false;
  235. }
  236. }
  237. /// This method sets the document password, including the user password for access restrictions
  238. /// and the owner password for granting permissions.
  239. ///
  240. /// - To enable permissions like printing or copying, the owner password must be set; otherwise,
  241. /// the settings will not take effect.
  242. ///
  243. /// example:
  244. /// ```dart
  245. /// bool result = controller.document.setPassword(
  246. /// userPassword : '1234',
  247. /// ownerPassword : '4321',
  248. /// allowsPrinting : false,
  249. /// allowsCopying : false,
  250. /// encryptAlgo = CPDFDocumentEncryptAlgo.rc4
  251. /// );
  252. /// ```
  253. Future<bool> setPassword({
  254. String? userPassword,
  255. String? ownerPassword,
  256. bool allowsPrinting = true,
  257. bool allowsCopying = true,
  258. CPDFDocumentEncryptAlgo encryptAlgo = CPDFDocumentEncryptAlgo.rc4
  259. }) async {
  260. try{
  261. return await _channel.invokeMethod('set_password', {
  262. 'user_password' : userPassword,
  263. 'owner_password' : ownerPassword,
  264. 'allows_printing' : allowsPrinting,
  265. 'allows_copying' : allowsCopying,
  266. 'encrypt_algo' : encryptAlgo.name
  267. });
  268. } on PlatformException catch (e) {
  269. debugPrint(e.message);
  270. return false;
  271. }
  272. }
  273. /// Get the encryption algorithm of the current document
  274. ///
  275. /// example:
  276. /// ```dart
  277. /// CPDFDocumentEncryptAlgo encryptAlgo = await controller.document.getEncryptAlgo();
  278. /// ```
  279. Future<CPDFDocumentEncryptAlgo> getEncryptAlgo() async {
  280. String encryptAlgoStr = await _channel.invokeMethod('get_encrypt_algorithm');
  281. return CPDFDocumentEncryptAlgo.values.where((e) => e.name == encryptAlgoStr).first;
  282. }
  283. /// Create document watermarks, including text watermarks and image watermarks
  284. ///
  285. /// - Add Text Watermark Example:
  286. /// ```dart
  287. /// await controller.document.createWatermark(CPDFWatermark.text(
  288. /// textContent: 'Flutter',
  289. /// scale: 1.0,
  290. /// fontSize: 50,
  291. /// textColor: Colors.deepOrange,
  292. /// pages: [0, 1, 2, 3,8,9]));
  293. /// ```
  294. ///
  295. /// - Add Image Watermark Example:
  296. /// ```dart
  297. /// File imageFile = await extractAsset(context, 'images/logo.png');
  298. /// await controller.document.createWatermark(CPDFWatermark.image(
  299. /// imagePath: imageFile.path,
  300. /// pages: [0, 1, 2, 3],
  301. /// horizontalSpacing: 50,
  302. /// verticalSpacing: 50,
  303. /// horizontalAlignment: CPDFWatermarkHorizontalAlignment.center,
  304. /// verticalAlignment: CPDFWatermarkVerticalAlignment.center,
  305. /// ));
  306. /// ```
  307. Future<bool> createWatermark(CPDFWatermark watermark) async {
  308. return await _channel.invokeMethod('create_watermark', watermark.toJson());
  309. }
  310. /// remove all watermark
  311. ///
  312. /// example:
  313. /// ```dart
  314. /// await controller.document.removeAllWatermarks();
  315. /// ```
  316. Future<void> removeAllWatermarks() async{
  317. return await _channel.invokeMethod('remove_all_watermarks');
  318. }
  319. Future<void> close() async {
  320. if (!_isValid) return;
  321. await _channel.invokeMethod('close');
  322. debugPrint('ComPDFKit:CPDFDocument.close');
  323. _isValid = false;
  324. }
  325. }