media_compressor 1.1.0-beta.1 copy "media_compressor: ^1.1.0-beta.1" to clipboard
media_compressor: ^1.1.0-beta.1 copied to clipboard

A Flutter plugin for efficient image and video compression on Android, iOS, and Web.

example/lib/main.dart

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:media_compressor/media_compressor.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) => MaterialApp(
        debugShowCheckedModeBanner: false,
        home: const HomePage(),
      );
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final _picker = ImagePicker();
  Uint8List? _bytes;
  String? _status;

  Future<void> _pickAndCompress() async {
    final file = await _picker.pickImage(source: ImageSource.gallery);
    if (file == null) return;
    setState(() => _status = 'Compressing...');
    final result = await MediaCompressor.compressImage(
      ImageCompressionConfig(
        path: file.path,
        quality: 70,
        maxWidth: 1920,
        maxHeight: 1080,
      ),
    );
    if (result.isSuccess) {
      // Cross-platform read (file path on mobile, blob URL on web).
      final out = XFile(result.path!);
      final bytes = await out.readAsBytes();
      if (!mounted) return;
      setState(() {
        _bytes = bytes;
        _status = 'Done — ${(bytes.length / 1024).toStringAsFixed(1)} KB';
      });
      await MediaCompressor.release(result.path!);
    } else {
      if (!mounted) return;
      setState(() => _status = 'Failed: ${result.error?.message}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Media Compressor')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            if (_bytes != null)
              SizedBox(height: 240, child: Image.memory(_bytes!)),
            if (_status != null) Padding(
              padding: const EdgeInsets.all(12),
              child: Text(_status!),
            ),
            ElevatedButton(
              onPressed: _pickAndCompress,
              child: const Text('Pick & compress image'),
            ),
          ],
        ),
      ),
    );
  }
}

// // Cross-platform Media Compressor example (Web + Android + iOS + Desktop).
// //
// // Web compatibility notes:
// //  - No `dart:io`. Sizes/bytes go through `XFile` (handles file paths on
// //    mobile AND blob URLs on web).
// //  - Image previews use `Image.memory` (platform agnostic).
// //  - Video playback uses `video_player` via a conditional factory.
// //  - Real progress comes from the `native_compressor/progress` EventChannel
// //    (Android + Web). iOS emits no progress yet.

// import 'dart:async';
// import 'package:flutter/material.dart';
// import 'package:flutter/services.dart';
// import 'package:image_picker/image_picker.dart'; // exports XFile
// import 'package:media_compressor/media_compressor.dart';
// import 'package:media_compressor_example/video_payer_example.dart';


// void main() {
//   WidgetsFlutterBinding.ensureInitialized();
//   runApp(const MyApp());
// }

// class MyApp extends StatelessWidget {
//   const MyApp({super.key});

//   @override
//   Widget build(BuildContext context) {
//     return MaterialApp(
//       title: 'Media Compressor Demo',
//       debugShowCheckedModeBanner: false,
//       theme: ThemeData(
//         useMaterial3: true,
//         colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
//       ),
//       home: const CompressorDemo(),
//     );
//   }
// }

// class CompressorDemo extends StatefulWidget {
//   const CompressorDemo({super.key});

//   @override
//   State<CompressorDemo> createState() => _CompressorDemoState();
// }

// class _CompressorDemoState extends State<CompressorDemo> {
//   final ImagePicker _picker = ImagePicker();

//   static const EventChannel _progressChannel =
//       EventChannel('native_compressor/progress');
//   StreamSubscription<dynamic>? _progressSub;

//   XFile? _originalFile;
//   String? _compressedPath;

//   Uint8List? _originalImageBytes;
//   Uint8List? _compressedImageBytes;

//   int? _originalSize;
//   int? _compressedSize;

//   bool _isCompressing = false;
//   double _progress = 0.0;
//   String _selectedType = 'image';

//   int _imageQuality = 80;
//   VideoQuality _videoQuality = VideoQuality.medium;

//   @override
//   void dispose() {
//     _progressSub?.cancel();
//     super.dispose();
//   }

//   void _listenProgress() {
//     _progressSub?.cancel();
//     _progressSub = _progressChannel.receiveBroadcastStream().listen(
//       (event) {
//         if (!_isCompressing || !mounted) return;
//         if (event is Map && event['progress'] != null) {
//           setState(() => _progress = (event['progress'] as num).toDouble());
//         }
//       },
//       onError: (_) {},
//     );
//   }

//   Future<void> _pickFile() async {
//     try {
//       final XFile? file = _selectedType == 'image'
//           ? await _picker.pickImage(source: ImageSource.gallery)
//           : await _picker.pickVideo(source: ImageSource.gallery);
//       if (file == null) return;

//       final size = await file.length();
//       Uint8List? imgBytes;
//       if (_selectedType == 'image') {
//         imgBytes = await file.readAsBytes();
//       }

//       setState(() {
//         _originalFile = file;
//         _originalSize = size;
//         _originalImageBytes = imgBytes;
//         _compressedPath = null;
//         _compressedSize = null;
//         _compressedImageBytes = null;
//         _progress = 0.0;
//       });

//       if (_selectedType == 'image') {
//         await _compressImage();
//       } else {
//         await _compressVideo();
//       }
//     } catch (e) {
//       _showError('Failed to pick file: $e');
//     }
//   }

//   Future<void> _compressImage() async {
//     final original = _originalFile;
//     if (original == null) return;

//     setState(() {
//       _isCompressing = true;
//       _progress = 0.0;
//     });
//     _listenProgress();

//     try {
//       final result = await MediaCompressor.compressImage(
//         ImageCompressionConfig(
//           path: original.path,
//           quality: _imageQuality,
//           maxWidth: 1920,
//           maxHeight: 1080,
//         ),
//       );

//       if (result.isSuccess) {
//         final out = XFile(result.path!);
//         final bytes = await out.readAsBytes();
//         if (!mounted) return;
//         setState(() {
//           _compressedPath = result.path;
//           _compressedImageBytes = bytes;
//           _compressedSize = bytes.length;
//           _progress = 1.0;
//           _isCompressing = false;
//         });
//       } else {
//         throw Exception(result.error?.message ?? 'Compression failed');
//       }
//     } catch (e) {
//       if (mounted) setState(() => _isCompressing = false);
//       _showError('Compression failed: $e');
//     }
//   }

//   Future<void> _compressVideo() async {
//     final original = _originalFile;
//     if (original == null) return;

//     setState(() {
//       _isCompressing = true;
//       _progress = 0.0;
//     });
//     _listenProgress();

//     try {
//       final result = await MediaCompressor.compressVideo(
//         VideoCompressionConfig(
//           path: original.path,
//           quality: _videoQuality,
//         ),
//       );

//       if (result.isSuccess) {
//         final out = XFile(result.path!);
//         final compressedSize = await out.length();
//         if (!mounted) return;
//         setState(() {
//           _compressedPath = result.path;
//           _compressedSize = compressedSize;
//           _progress = 1.0;
//           _isCompressing = false;
//         });

//         if (mounted) {
//           Navigator.push(
//             context,
//             MaterialPageRoute(
//               builder: (_) => VideoCompareScreen(
//                 originalPath: original.path,
//                 compressedPath: result.path!,
//                 originalSize: _originalSize ?? 0,
//                 compressedSize: compressedSize,
//               ),
//             ),
//           );
//         }
//       } else {
//         throw Exception(result.error?.message ?? 'Compression failed');
//       }
//     } catch (e) {
//       if (mounted) setState(() => _isCompressing = false);
//       _showError('Compression failed: $e');
//     }
//   }

//   String _formatBytes(int bytes) {
//     if (bytes < 1024) return '$bytes B';
//     if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
//     return '${(bytes / (1024 * 1024)).toStringAsFixed(2)} MB';
//   }

//   void _showError(String message) {
//     if (!mounted) return;
//     ScaffoldMessenger.of(context).showSnackBar(
//       SnackBar(content: Text(message), backgroundColor: Colors.red),
//     );
//   }

//   void _resetState() {
//     setState(() {
//       _originalFile = null;
//       _compressedPath = null;
//       _originalImageBytes = null;
//       _compressedImageBytes = null;
//       _originalSize = null;
//       _compressedSize = null;
//       _progress = 0.0;
//     });
//   }

//   @override
//   Widget build(BuildContext context) {
//     final reduction = (_originalSize != null &&
//             _compressedSize != null &&
//             _originalSize! > 0)
//         ? ((1 - (_compressedSize! / _originalSize!)) * 100).toInt()
//         : null;

//     return Scaffold(
//       appBar: AppBar(title: const Text('Media Compressor'), centerTitle: true),
//       body: SingleChildScrollView(
//         padding: const EdgeInsets.all(20),
//         child: Column(
//           crossAxisAlignment: CrossAxisAlignment.stretch,
//           children: [
//             Row(
//               children: [
//                 Expanded(
//                   child: ChoiceChip(
//                     label: const Text('Image'),
//                     selected: _selectedType == 'image',
//                     onSelected: _isCompressing
//                         ? null
//                         : (_) {
//                             setState(() => _selectedType = 'image');
//                             _resetState();
//                           },
//                   ),
//                 ),
//                 const SizedBox(width: 12),
//                 Expanded(
//                   child: ChoiceChip(
//                     label: const Text('Video'),
//                     selected: _selectedType == 'video',
//                     onSelected: _isCompressing
//                         ? null
//                         : (_) {
//                             setState(() => _selectedType = 'video');
//                             _resetState();
//                           },
//                   ),
//                 ),
//               ],
//             ),
//             const SizedBox(height: 20),
//             ElevatedButton.icon(
//               onPressed: _isCompressing ? null : _pickFile,
//               icon: Icon(
//                   _selectedType == 'image' ? Icons.image : Icons.video_library),
//               label: Text(
//                   'Select ${_selectedType == 'image' ? 'Image' : 'Video'}'),
//               style: ElevatedButton.styleFrom(padding: const EdgeInsets.all(16)),
//             ),
//             const SizedBox(height: 20),
//             if (_selectedType == 'image') ...[
//               const Text('Image Quality',
//                   style: TextStyle(fontWeight: FontWeight.w500)),
//               Row(
//                 children: [
//                   const Text('Low', style: TextStyle(fontSize: 12)),
//                   Expanded(
//                     child: Slider(
//                       value: _imageQuality.toDouble(),
//                       min: 10,
//                       max: 100,
//                       divisions: 18,
//                       label: '$_imageQuality%',
//                       onChanged: _isCompressing
//                           ? null
//                           : (v) => setState(() => _imageQuality = v.toInt()),
//                       onChangeEnd: (_) {
//                         if (_originalFile != null) _compressImage();
//                       },
//                     ),
//                   ),
//                   const Text('High', style: TextStyle(fontSize: 12)),
//                 ],
//               ),
//             ] else ...[
//               const Text('Video Quality',
//                   style: TextStyle(fontWeight: FontWeight.w500)),
//               const SizedBox(height: 8),
//               SegmentedButton<VideoQuality>(
//                 segments: const [
//                   ButtonSegment(value: VideoQuality.low, label: Text('Low')),
//                   ButtonSegment(
//                       value: VideoQuality.medium, label: Text('Medium')),
//                   ButtonSegment(value: VideoQuality.high, label: Text('High')),
//                 ],
//                 selected: {_videoQuality},
//                 onSelectionChanged: _isCompressing
//                     ? null
//                     : (sel) {
//                         setState(() => _videoQuality = sel.first);
//                         if (_originalFile != null) _compressVideo();
//                       },
//               ),
//             ],
//             if (_isCompressing) ...[
//               const SizedBox(height: 24),
//               const Text('Compressing...',
//                   textAlign: TextAlign.center,
//                   style:
//                       TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
//               const SizedBox(height: 12),
//               LinearProgressIndicator(
//                 value: _progress == 0 ? null : _progress,
//                 minHeight: 8,
//                 borderRadius: BorderRadius.circular(4),
//               ),
//               const SizedBox(height: 8),
//               Text('${(_progress * 100).toInt()}%',
//                   textAlign: TextAlign.center),
//             ],
//             if (_originalSize != null) ...[
//               const SizedBox(height: 24),
//               Row(
//                 children: [
//                   Expanded(
//                     child: _SizeCard(
//                         label: 'Before',
//                         size: _formatBytes(_originalSize!),
//                         color: Colors.grey),
//                   ),
//                   const SizedBox(width: 12),
//                   Expanded(
//                     child: _SizeCard(
//                       label: 'After',
//                       size: _compressedSize != null
//                           ? _formatBytes(_compressedSize!)
//                           : '...',
//                       color: Colors.green,
//                     ),
//                   ),
//                 ],
//               ),
//               if (reduction != null) ...[
//                 const SizedBox(height: 8),
//                 Text('$reduction% smaller',
//                     textAlign: TextAlign.center,
//                     style: const TextStyle(
//                         fontWeight: FontWeight.w600, color: Colors.green)),
//               ],
//             ],
//             if (_selectedType == 'image' && _originalImageBytes != null) ...[
//               const SizedBox(height: 24),
//               Row(
//                 children: [
//                   Expanded(
//                     child: _ImagePreview(
//                         label: 'Original',
//                         bytes: _originalImageBytes,
//                         isLoading: false),
//                   ),
//                   const SizedBox(width: 12),
//                   Expanded(
//                     child: _ImagePreview(
//                         label: 'Compressed',
//                         bytes: _compressedImageBytes,
//                         isLoading: _isCompressing),
//                   ),
//                 ],
//               ),
//             ],
//           ],
//         ),
//       ),
//     );
//   }
// }

// class _SizeCard extends StatelessWidget {
//   const _SizeCard(
//       {required this.label, required this.size, required this.color});
//   final String label;
//   final String size;
//   final Color color;

//   @override
//   Widget build(BuildContext context) {
//     return Container(
//       padding: const EdgeInsets.all(16),
//       decoration: BoxDecoration(
//         color: color.withValues(alpha: 0.12),
//         borderRadius: BorderRadius.circular(12),
//       ),
//       child: Column(
//         children: [
//           Text(label, style: const TextStyle(fontSize: 14)),
//           const SizedBox(height: 4),
//           Text(size,
//               style:
//                   const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
//         ],
//       ),
//     );
//   }
// }

// class _ImagePreview extends StatelessWidget {
//   const _ImagePreview(
//       {required this.label, required this.bytes, required this.isLoading});
//   final String label;
//   final Uint8List? bytes;
//   final bool isLoading;

//   @override
//   Widget build(BuildContext context) {
//     return Column(
//       children: [
//         Text(label, style: const TextStyle(fontWeight: FontWeight.w500)),
//         const SizedBox(height: 8),
//         AspectRatio(
//           aspectRatio: 1,
//           child: ClipRRect(
//             borderRadius: BorderRadius.circular(8),
//             child: bytes != null
//                 ? Image.memory(bytes!, fit: BoxFit.cover)
//                 : Container(
//                     color: Colors.grey.shade200,
//                     child: isLoading
//                         ? const Center(child: CircularProgressIndicator())
//                         : null,
//                   ),
//           ),
//         ),
//       ],
//     );
//   }
// }
37
likes
0
points
672
downloads

Publisher

verified publisherharikrishnancr.com

Weekly Downloads

A Flutter plugin for efficient image and video compression on Android, iOS, and Web.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_web_plugins, plugin_platform_interface, web

More

Packages that depend on media_compressor

Packages that implement media_compressor