megapdf_flutter 0.0.2
megapdf_flutter: ^0.0.2 copied to clipboard
Flutter plugin for MegaPDF API to manipulate PDF files with conversion, compression, merging, splitting, protection, and other functionalities.
example/lib/main.dart
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:megapdf_flutter/megapdf_flutter.dart';
import 'package:megapdf_flutter/src/models/models.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MegaPDF Example',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
home: const MegaPdfDemoHome(),
);
}
}
class MegaPdfDemoHome extends StatefulWidget {
const MegaPdfDemoHome({Key? key}) : super(key: key);
@override
State<MegaPdfDemoHome> createState() => _MegaPdfDemoHomeState();
}
class _MegaPdfDemoHomeState extends State<MegaPdfDemoHome> {
final MegaPdf _megaPdf = MegaPdf();
bool _isInitialized = false;
bool _isLoading = false;
String _result = '';
String? _outputFilePath;
final TextEditingController _apiKeyController = TextEditingController(
);
@override
void initState() {
super.initState();
_checkInitialization();
_requestPermissions();
}
Future<void> _requestPermissions() async {
if (Platform.isAndroid || Platform.isIOS) {
await [Permission.storage].request();
}
}
Future<void> _checkInitialization() async {
setState(() {
_isLoading = true;
});
try {
final initialized = await _megaPdf.initializeFromPreferences();
setState(() {
_isInitialized = initialized;
});
} catch (e) {
debugPrint('Error checking initialization: $e');
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _initializeSdk() async {
if (_apiKeyController.text.isEmpty) {
_showError('Please enter an API key');
return;
}
setState(() {
_isLoading = true;
});
try {
await _megaPdf.initialize(apiKey: _apiKeyController.text);
setState(() {
_isInitialized = true;
_result = 'SDK initialized successfully';
});
} catch (e) {
_showError('Failed to initialize SDK: $e');
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<File?> _pickPdfFile() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['pdf'],
);
if (result != null && result.files.single.path != null) {
return File(result.files.single.path!);
}
return null;
}
Future<List<File>?> _pickMultiplePdfFiles() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['pdf'],
allowMultiple: true,
);
if (result != null) {
return result.paths
.whereType<String>()
.map((path) => File(path))
.toList();
}
return null;
}
Future<void> _compressPdf() async {
if (!_isInitialized) {
_showError('Please initialize the SDK first');
return;
}
setState(() {
_isLoading = true;
_result = 'Compressing PDF...';
_outputFilePath = null;
});
try {
final file = await _pickPdfFile();
if (file == null) {
setState(() {
_result = 'No file selected';
_isLoading = false;
});
return;
}
final response = await _megaPdf.compressPdf(
file: file,
options: CompressOptions(quality: 'medium'),
);
if (response.success && response.fileUrl != null) {
final outputFile = await _downloadFile(
response.fileUrl!,
'compressed.pdf',
);
setState(() {
_result =
'PDF compressed successfully.\nOriginal size: ${response.get<int>('originalSize')}\nCompressed size: ${response.get<int>('compressedSize')}\nCompression ratio: ${response.get<String>('compressionRatio')}';
_outputFilePath = outputFile.path;
});
} else {
setState(() {
_result = 'Compression failed: ${response.error}';
});
}
} catch (e) {
setState(() {
_result = 'Error during compression: $e';
});
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _mergePdfs() async {
if (!_isInitialized) {
_showError('Please initialize the SDK first');
return;
}
setState(() {
_isLoading = true;
_result = 'Merging PDFs...';
_outputFilePath = null;
});
try {
final files = await _pickMultiplePdfFiles();
if (files == null || files.isEmpty || files.length < 2) {
setState(() {
_result = 'Please select at least 2 PDF files';
_isLoading = false;
});
return;
}
final response = await _megaPdf.mergePdfs(files: files);
if (response.success && response.fileUrl != null) {
final outputFile = await _downloadFile(response.fileUrl!, 'merged.pdf');
setState(() {
_result = 'PDFs merged successfully.\nMerged ${files.length} files.';
_outputFilePath = outputFile.path;
});
} else {
setState(() {
_result = 'Merge failed: ${response.error}';
});
}
} catch (e) {
setState(() {
_result = 'Error during merging: $e';
});
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _convertPdf() async {
if (!_isInitialized) {
_showError('Please initialize the SDK first');
return;
}
setState(() {
_isLoading = true;
_result = 'Converting PDF...';
_outputFilePath = null;
});
try {
final file = await _pickPdfFile();
if (file == null) {
setState(() {
_result = 'No file selected';
_isLoading = false;
});
return;
}
// Show a dialog to select output format
final outputFormat = await _showFormatSelectionDialog();
if (outputFormat == null) {
setState(() {
_result = 'No output format selected';
_isLoading = false;
});
return;
}
final response = await _megaPdf.convertPdf(
file: file,
outputFormat: outputFormat,
options: ConversionOptions(ocr: false, quality: 90),
);
if (response.success && response.fileUrl != null) {
final outputFile = await _downloadFile(
response.fileUrl!,
'converted.$outputFormat',
);
setState(() {
_result = 'PDF converted successfully to $outputFormat';
_outputFilePath = outputFile.path;
});
} else {
setState(() {
_result = 'Conversion failed: ${response.error}';
});
}
} catch (e) {
setState(() {
_result = 'Error during conversion: $e';
});
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<String?> _showFormatSelectionDialog() async {
return showDialog<String>(
context: context,
builder:
(context) => SimpleDialog(
title: const Text('Select output format'),
children:
['docx', 'xlsx', 'pptx', 'html', 'txt', 'jpg', 'png']
.map(
(format) => SimpleDialogOption(
onPressed: () => Navigator.pop(context, format),
child: Text(format.toUpperCase()),
),
)
.toList(),
),
);
}
Future<File> _downloadFile(String url, String fileName) async {
final directory = await getApplicationDocumentsDirectory();
final filePath = '${directory.path}/$fileName';
final file = File(filePath);
// If the URL is relative, make it absolute
if (url.startsWith('/')) {
url = '${_megaPdf.baseUrl}$url';
}
// Download the file
try {
await _megaPdf.downloadFile(url, filePath);
return file;
} catch (e) {
throw Exception('Failed to download file: $e');
}
}
Future<void> _protectPdf() async {
if (!_isInitialized) {
_showError('Please initialize the SDK first');
return;
}
setState(() {
_isLoading = true;
_result = 'Protecting PDF...';
_outputFilePath = null;
});
try {
final file = await _pickPdfFile();
if (file == null) {
setState(() {
_result = 'No file selected';
_isLoading = false;
});
return;
}
// Show a dialog to enter password
final password = await _showPasswordDialog();
if (password == null || password.isEmpty) {
setState(() {
_result = 'Password is required';
_isLoading = false;
});
return;
}
final response = await _megaPdf.protectPdf(
file: file,
password: password,
options: ProtectionOptions(
allowPrinting: true,
allowCopying: false,
allowEditing: false,
),
);
if (response.success && response.fileUrl != null) {
final outputFile = await _downloadFile(
response.fileUrl!,
'protected.pdf',
);
setState(() {
_result = 'PDF protected successfully with password';
_outputFilePath = outputFile.path;
});
} else {
setState(() {
_result = 'Protection failed: ${response.error}';
});
}
} catch (e) {
setState(() {
_result = 'Error during protection: $e';
});
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<String?> _showPasswordDialog() async {
final passwordController = TextEditingController();
return showDialog<String>(
context: context,
builder:
(context) => AlertDialog(
title: const Text('Enter password'),
content: TextField(
controller: passwordController,
decoration: const InputDecoration(hintText: 'Password'),
obscureText: true,
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL'),
),
TextButton(
onPressed:
() => Navigator.pop(context, passwordController.text),
child: const Text('OK'),
),
],
),
);
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message), backgroundColor: Colors.red),
);
}
Future<void> _openOutputFile() async {
if (_outputFilePath != null) {
final uri = Uri.file(_outputFilePath!);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
_showError('Cannot open file');
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('MegaPDF Demo')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (!_isInitialized) ...[
TextField(
controller: _apiKeyController,
decoration: const InputDecoration(
labelText: 'API Key',
hintText: 'Enter your MegaPDF API key',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _isLoading ? null : _initializeSdk,
child: const Text('Initialize SDK'),
),
] else ...[
Text(
'API Key: ${_megaPdf.apiKey!.substring(0, 8)}...',
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: _isLoading ? null : _compressPdf,
child: const Text('Compress PDF'),
),
ElevatedButton(
onPressed: _isLoading ? null : _mergePdfs,
child: const Text('Merge PDFs'),
),
ElevatedButton(
onPressed: _isLoading ? null : _convertPdf,
child: const Text('Convert PDF'),
),
ElevatedButton(
onPressed: _isLoading ? null : _protectPdf,
child: const Text('Protect PDF'),
),
],
),
],
const SizedBox(height: 16),
Expanded(
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: SingleChildScrollView(
child:
_isLoading
? const Center(child: CircularProgressIndicator())
: SelectableText(_result),
),
),
),
if (_outputFilePath != null) ...[
const SizedBox(height: 16),
OutlinedButton.icon(
onPressed: _openOutputFile,
icon: const Icon(Icons.open_in_new),
label: const Text('Open Output File'),
),
],
],
),
),
);
}
}